Compare commits
30 commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
6ec9fa13fc | ||
|
|
ec2e1c9865 | ||
|
|
670fad9bbf | ||
|
|
1d762222e7 | ||
|
|
2263ba7680 | ||
|
|
5deaf4fc7a | ||
|
|
a74f616fd7 | ||
|
|
6440b8fe42 | ||
|
|
04bd1b3d08 | ||
|
|
9c9e79587b | ||
|
|
07ce689a8c | ||
|
|
c99101a29d | ||
|
|
9a52fd937a | ||
|
|
621438a876 | ||
|
|
438ad7bd65 | ||
|
|
63079ed187 | ||
|
|
dff9bcb43c | ||
|
|
f1cb5c5c93 | ||
|
|
6d34cbe33c | ||
|
|
9c10ff9b1c | ||
|
|
a78ef46133 | ||
|
|
c03c49a539 | ||
|
|
7c4e9222ef | ||
|
|
42d495a7e8 | ||
|
|
d6d4ddb15b | ||
|
|
c6139214eb | ||
|
|
97aab0fcca | ||
|
|
8a921dfb2d | ||
|
|
b1aada9b0e | ||
|
|
99897636a1 |
76 changed files with 4537 additions and 42 deletions
66
.claude/settings.local.json
Normal file
66
.claude/settings.local.json
Normal file
|
|
@ -0,0 +1,66 @@
|
||||||
|
{
|
||||||
|
"permissions": {
|
||||||
|
"allow": [
|
||||||
|
"Bash(where git go gh php composer node pnpm)",
|
||||||
|
"Bash(go version:*)",
|
||||||
|
"Bash(git --version)",
|
||||||
|
"Bash(gh --version:*)",
|
||||||
|
"Bash(powershell -ExecutionPolicy Bypass -File scripts/install-core.ps1:*)",
|
||||||
|
"Bash(git ls-remote:*)",
|
||||||
|
"Bash(C:/Users/snide/AppData/Local/Programs/core/core.exe --help)",
|
||||||
|
"Bash(powershell -Command \"cd packages/core-php; composer install\")",
|
||||||
|
"Bash(powershell -Command:*)",
|
||||||
|
"Bash(gh issue list:*)",
|
||||||
|
"Bash(git add:*)",
|
||||||
|
"Bash(gh issue view:*)",
|
||||||
|
"Bash(core doctor)",
|
||||||
|
"Bash(core dev status:*)",
|
||||||
|
"Bash(core pkg list:*)",
|
||||||
|
"Bash(core php test --help:*)",
|
||||||
|
"Bash(core dev health:*)",
|
||||||
|
"Bash(core php test)",
|
||||||
|
"Bash(git push:*)",
|
||||||
|
"Bash(go build:*)",
|
||||||
|
"Bash(gh issue create:*)",
|
||||||
|
"Bash(git checkout:*)",
|
||||||
|
"Bash(git stash:*)",
|
||||||
|
"Bash(gh api:*)",
|
||||||
|
"Bash(gh pr checks:*)",
|
||||||
|
"Bash(git fetch:*)",
|
||||||
|
"Bash(git rebase:*)",
|
||||||
|
"Bash(git branch:*)",
|
||||||
|
"Bash(gh pr view:*)",
|
||||||
|
"Bash(git pull:*)",
|
||||||
|
"Bash(gh run list:*)",
|
||||||
|
"Bash(gh run view:*)",
|
||||||
|
"Bash(gh search issues:*)",
|
||||||
|
"Bash(gh search prs:*)",
|
||||||
|
"Bash(gh issue comment:*)",
|
||||||
|
"Bash(gh issue edit:*)",
|
||||||
|
"Bash(gh issue close:*)",
|
||||||
|
"Bash(gh pr create:*)",
|
||||||
|
"Bash(gh pr merge:*)",
|
||||||
|
"Bash(composer test:*)",
|
||||||
|
"Bash(composer lint:*)",
|
||||||
|
"Bash(composer analyse:*)",
|
||||||
|
"Bash(composer install:*)",
|
||||||
|
"Bash(git commit:*)",
|
||||||
|
"Bash(git status:*)",
|
||||||
|
"Bash(git diff:*)",
|
||||||
|
"Bash(git log:*)",
|
||||||
|
"Bash(git rev-parse:*)",
|
||||||
|
"Bash(go test:*)",
|
||||||
|
"Bash(go build:*)",
|
||||||
|
"Bash(go vet:*)",
|
||||||
|
"Bash(go mod tidy:*)",
|
||||||
|
"Bash(golangci-lint:*)",
|
||||||
|
"Bash(task test:*)",
|
||||||
|
"Bash(task cov:*)",
|
||||||
|
"Bash(task lint:*)",
|
||||||
|
"Bash(task fmt:*)",
|
||||||
|
"Bash(task qa:*)",
|
||||||
|
"Bash(task cli:build:*)",
|
||||||
|
"Bash(task mod:tidy:*)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
13
.coderabbit.yaml
Normal file
13
.coderabbit.yaml
Normal file
|
|
@ -0,0 +1,13 @@
|
||||||
|
# CodeRabbit Configuration
|
||||||
|
# Inherits from: https://github.com/host-uk/coderabbit/.coderabbit.yaml
|
||||||
|
|
||||||
|
reviews:
|
||||||
|
review_status: false
|
||||||
|
|
||||||
|
path_instructions:
|
||||||
|
- path: "scripts/**"
|
||||||
|
instructions: "Setup scripts - ensure cross-platform compatibility (macOS, Linux, Windows)"
|
||||||
|
- path: "doc/**"
|
||||||
|
instructions: "Documentation - check for accuracy and British English spelling"
|
||||||
|
- path: ".github/**"
|
||||||
|
instructions: "GitHub config - validate workflow syntax and action versions"
|
||||||
157
.core/github.yaml
Normal file
157
.core/github.yaml
Normal file
|
|
@ -0,0 +1,157 @@
|
||||||
|
# GitHub repository configuration for Host UK organisation.
|
||||||
|
# Used by: core setup github
|
||||||
|
#
|
||||||
|
# Environment variables can be referenced using ${VAR} or ${VAR:-default} syntax.
|
||||||
|
|
||||||
|
version: 1
|
||||||
|
|
||||||
|
# Organisation-standard labels
|
||||||
|
labels:
|
||||||
|
# Priority labels
|
||||||
|
- name: "priority:critical"
|
||||||
|
color: "b60205"
|
||||||
|
description: "Must be fixed immediately"
|
||||||
|
- name: "priority:high"
|
||||||
|
color: "d93f0b"
|
||||||
|
description: "Should be fixed soon"
|
||||||
|
- name: "priority:medium"
|
||||||
|
color: "fbca04"
|
||||||
|
description: "Normal priority"
|
||||||
|
- name: "priority:low"
|
||||||
|
color: "0e8a16"
|
||||||
|
description: "Nice to have"
|
||||||
|
|
||||||
|
# Type labels
|
||||||
|
- name: "type:bug"
|
||||||
|
color: "d73a4a"
|
||||||
|
description: "Something isn't working"
|
||||||
|
- name: "type:feature"
|
||||||
|
color: "a2eeef"
|
||||||
|
description: "New feature or request"
|
||||||
|
- name: "type:enhancement"
|
||||||
|
color: "84b6eb"
|
||||||
|
description: "Improvement to existing feature"
|
||||||
|
- name: "type:docs"
|
||||||
|
color: "0075ca"
|
||||||
|
description: "Documentation improvements"
|
||||||
|
- name: "type:refactor"
|
||||||
|
color: "d4c5f9"
|
||||||
|
description: "Code refactoring"
|
||||||
|
- name: "type:test"
|
||||||
|
color: "bfd4f2"
|
||||||
|
description: "Test improvements"
|
||||||
|
- name: "type:chore"
|
||||||
|
color: "fef2c0"
|
||||||
|
description: "Maintenance tasks"
|
||||||
|
- name: "type:security"
|
||||||
|
color: "ee0701"
|
||||||
|
description: "Security-related issue"
|
||||||
|
|
||||||
|
# Status labels
|
||||||
|
- name: "status:blocked"
|
||||||
|
color: "b60205"
|
||||||
|
description: "Blocked by another issue or external factor"
|
||||||
|
- name: "status:in-progress"
|
||||||
|
color: "fbca04"
|
||||||
|
description: "Currently being worked on"
|
||||||
|
- name: "status:review"
|
||||||
|
color: "6f42c1"
|
||||||
|
description: "Ready for review"
|
||||||
|
- name: "status:ready"
|
||||||
|
color: "0e8a16"
|
||||||
|
description: "Ready for development"
|
||||||
|
|
||||||
|
# Agent labels (for AI-assisted development)
|
||||||
|
- name: "agent:ready"
|
||||||
|
color: "00ff00"
|
||||||
|
description: "Task ready for AI agent pickup"
|
||||||
|
- name: "agent:assigned"
|
||||||
|
color: "1d76db"
|
||||||
|
description: "Task assigned to AI agent"
|
||||||
|
- name: "agent:blocked"
|
||||||
|
color: "e99695"
|
||||||
|
description: "Agent needs human input"
|
||||||
|
- name: "agent:completed"
|
||||||
|
color: "0e8a16"
|
||||||
|
description: "Agent completed the task"
|
||||||
|
|
||||||
|
# Scope labels
|
||||||
|
- name: "scope:api"
|
||||||
|
color: "c5def5"
|
||||||
|
description: "API changes"
|
||||||
|
- name: "scope:ui"
|
||||||
|
color: "bfdadc"
|
||||||
|
description: "User interface changes"
|
||||||
|
- name: "scope:db"
|
||||||
|
color: "d4c5f9"
|
||||||
|
description: "Database changes"
|
||||||
|
- name: "scope:infra"
|
||||||
|
color: "f9d0c4"
|
||||||
|
description: "Infrastructure changes"
|
||||||
|
- name: "scope:deps"
|
||||||
|
color: "fef2c0"
|
||||||
|
description: "Dependency updates"
|
||||||
|
|
||||||
|
# Workflow labels
|
||||||
|
- name: "breaking"
|
||||||
|
color: "b60205"
|
||||||
|
description: "Contains breaking changes"
|
||||||
|
- name: "good first issue"
|
||||||
|
color: "7057ff"
|
||||||
|
description: "Good for newcomers"
|
||||||
|
- name: "help wanted"
|
||||||
|
color: "008672"
|
||||||
|
description: "Extra attention is needed"
|
||||||
|
- name: "wontfix"
|
||||||
|
color: "ffffff"
|
||||||
|
description: "This will not be worked on"
|
||||||
|
- name: "duplicate"
|
||||||
|
color: "cfd3d7"
|
||||||
|
description: "This issue or pull request already exists"
|
||||||
|
|
||||||
|
# Webhooks (optional - set env vars to enable)
|
||||||
|
webhooks:
|
||||||
|
discord-push:
|
||||||
|
url: ${DISCORD_WEBHOOK_PUSH:-}
|
||||||
|
events:
|
||||||
|
- push
|
||||||
|
- release
|
||||||
|
content_type: json
|
||||||
|
|
||||||
|
discord-issues:
|
||||||
|
url: ${DISCORD_WEBHOOK_ISSUES:-}
|
||||||
|
events:
|
||||||
|
- issues
|
||||||
|
- issue_comment
|
||||||
|
- pull_request
|
||||||
|
- pull_request_review
|
||||||
|
content_type: json
|
||||||
|
|
||||||
|
# Branch protection rules
|
||||||
|
branch_protection:
|
||||||
|
- branch: main
|
||||||
|
required_reviews: 1
|
||||||
|
dismiss_stale: true
|
||||||
|
require_code_owner_reviews: false
|
||||||
|
enforce_admins: false
|
||||||
|
require_linear_history: false
|
||||||
|
allow_force_pushes: false
|
||||||
|
allow_deletions: false
|
||||||
|
require_conversation_resolution: true
|
||||||
|
|
||||||
|
- branch: dev
|
||||||
|
required_reviews: 1
|
||||||
|
dismiss_stale: true
|
||||||
|
require_code_owner_reviews: false
|
||||||
|
enforce_admins: false
|
||||||
|
require_linear_history: false
|
||||||
|
allow_force_pushes: false
|
||||||
|
allow_deletions: false
|
||||||
|
require_conversation_resolution: false
|
||||||
|
|
||||||
|
# Security settings
|
||||||
|
security:
|
||||||
|
dependabot_alerts: true
|
||||||
|
dependabot_security_updates: true
|
||||||
|
secret_scanning: true
|
||||||
|
push_protection: true
|
||||||
|
|
@ -19,6 +19,16 @@
|
||||||
"name": "package-status",
|
"name": "package-status",
|
||||||
"file": "skills/package-status.md",
|
"file": "skills/package-status.md",
|
||||||
"description": "Show status of all packages in the workspace"
|
"description": "Show status of all packages in the workspace"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "php-agent",
|
||||||
|
"file": "skills/php-agent.md",
|
||||||
|
"description": "Autonomous PHP development agent - picks up issues, implements, handles reviews, merges"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "go-agent",
|
||||||
|
"file": "skills/go-agent.md",
|
||||||
|
"description": "Autonomous Go development agent - picks up issues, implements, handles reviews, merges"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
|
|
||||||
|
|
|
||||||
415
.core/plugin/skills/go-agent.md
Normal file
415
.core/plugin/skills/go-agent.md
Normal file
|
|
@ -0,0 +1,415 @@
|
||||||
|
# Go Agent Skill
|
||||||
|
|
||||||
|
You are an autonomous Go development agent working on the Host UK Go projects (primarily the `core` CLI). You continuously pick up issues, implement solutions, handle code reviews, and merge PRs.
|
||||||
|
|
||||||
|
## Workflow Loop
|
||||||
|
|
||||||
|
This skill runs as a continuous loop:
|
||||||
|
|
||||||
|
```
|
||||||
|
1. CHECK PENDING PRs → Fix reviews if CodeRabbit commented
|
||||||
|
2. FIND ISSUE → Pick a Go issue from host-uk org
|
||||||
|
3. IMPLEMENT → Create branch, code, test, push
|
||||||
|
4. HANDLE REVIEW → Wait for/fix CodeRabbit feedback
|
||||||
|
5. MERGE → Merge when approved
|
||||||
|
6. REPEAT → Start next task
|
||||||
|
```
|
||||||
|
|
||||||
|
## State Management
|
||||||
|
|
||||||
|
Track your work with these variables:
|
||||||
|
- `PENDING_PRS`: PRs waiting for CodeRabbit review
|
||||||
|
- `CURRENT_ISSUE`: Issue currently being worked on
|
||||||
|
- `CURRENT_BRANCH`: Branch for current work
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 1: Check Pending PRs
|
||||||
|
|
||||||
|
Before starting new work, check if any of your pending PRs have CodeRabbit reviews ready.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# List your open PRs in the core repo
|
||||||
|
gh pr list --repo host-uk/core --author=@me --state=open --json number,title,headRefName,url
|
||||||
|
|
||||||
|
# For each PR, check CodeRabbit status
|
||||||
|
gh api repos/host-uk/core/commits/{sha}/status --jq '.statuses[] | select(.context | contains("coderabbit")) | {context, state, description}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### If CodeRabbit review is complete:
|
||||||
|
- **Success (no issues)**: Merge the PR
|
||||||
|
- **Has comments**: Fix the issues, commit, push, continue to next task
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check for new reviews
|
||||||
|
gh api repos/host-uk/core/pulls/{pr_number}/reviews --jq 'sort_by(.submitted_at) | .[-1] | {author: .user.login, state: .state, body: .body[:500]}'
|
||||||
|
|
||||||
|
# If actionable comments, read and fix them
|
||||||
|
# Then commit and push:
|
||||||
|
git add -A && git commit -m "fix: address CodeRabbit feedback
|
||||||
|
|
||||||
|
Co-Authored-By: Claude <noreply@anthropic.com>"
|
||||||
|
git push
|
||||||
|
```
|
||||||
|
|
||||||
|
### Merging PRs
|
||||||
|
```bash
|
||||||
|
# When CodeRabbit approves (status: success), merge without admin
|
||||||
|
gh pr merge {pr_number} --squash --repo host-uk/core
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 2: Find an Issue
|
||||||
|
|
||||||
|
Search for Go issues in the Host UK organization.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Find open issues labeled for Go
|
||||||
|
gh search issues --owner=host-uk --state=open --label="lang:go" --json number,title,repository,url --limit=10
|
||||||
|
|
||||||
|
# Or list issues in the core repo directly
|
||||||
|
gh issue list --repo host-uk/core --state=open --json number,title,labels,body --limit=20
|
||||||
|
|
||||||
|
# Check for agent-ready issues
|
||||||
|
gh issue list --repo host-uk/core --state=open --label="agent:ready" --json number,title,body
|
||||||
|
```
|
||||||
|
|
||||||
|
### Issue Selection Criteria
|
||||||
|
1. **Priority**: Issues with `priority:high` or `good-first-issue` labels
|
||||||
|
2. **Dependencies**: Check if issue depends on other incomplete work
|
||||||
|
3. **Scope**: Prefer issues that can be completed in one session
|
||||||
|
4. **Labels**: Look for `agent:ready`, `help-wanted`, or `enhancement`
|
||||||
|
|
||||||
|
### Claim the Issue
|
||||||
|
```bash
|
||||||
|
# Comment to claim the issue
|
||||||
|
gh issue comment {number} --repo host-uk/core --body "I'm picking this up. Starting work now."
|
||||||
|
|
||||||
|
# Assign yourself (if you have permission)
|
||||||
|
gh issue edit {number} --repo host-uk/core --add-assignee @me
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 3: Implement the Solution
|
||||||
|
|
||||||
|
### Setup Branch
|
||||||
|
```bash
|
||||||
|
# Navigate to the core package
|
||||||
|
cd packages/core
|
||||||
|
|
||||||
|
# Ensure you're on dev and up to date
|
||||||
|
git checkout dev && git pull
|
||||||
|
|
||||||
|
# Create feature branch
|
||||||
|
git checkout -b feature/issue-{number}-{short-description}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Development Workflow
|
||||||
|
1. **Read the code** - Understand the package structure
|
||||||
|
2. **Write tests first** - TDD approach when possible
|
||||||
|
3. **Implement the solution** - Follow Go best practices
|
||||||
|
4. **Run tests** - Ensure all tests pass
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Run tests (using Task)
|
||||||
|
task test
|
||||||
|
|
||||||
|
# Or directly with go
|
||||||
|
go test ./...
|
||||||
|
|
||||||
|
# Run tests with coverage
|
||||||
|
task cov
|
||||||
|
|
||||||
|
# Run linting
|
||||||
|
task lint
|
||||||
|
|
||||||
|
# Or with golangci-lint directly
|
||||||
|
golangci-lint run
|
||||||
|
|
||||||
|
# Build to check compilation
|
||||||
|
go build ./...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Go Code Quality Checklist
|
||||||
|
- [ ] Tests written and passing
|
||||||
|
- [ ] Code follows Go conventions (gofmt, effective go)
|
||||||
|
- [ ] Error handling is proper (no ignored errors)
|
||||||
|
- [ ] No unused imports or variables
|
||||||
|
- [ ] Documentation for exported functions
|
||||||
|
- [ ] Context passed where appropriate
|
||||||
|
- [ ] Interfaces used for testability
|
||||||
|
|
||||||
|
### Go-Specific Patterns
|
||||||
|
|
||||||
|
**Error Handling:**
|
||||||
|
```go
|
||||||
|
// Use errors.E for contextual errors
|
||||||
|
return errors.E("service.method", "what failed", err)
|
||||||
|
|
||||||
|
// Or errors.Wrap for wrapping
|
||||||
|
return errors.Wrap(err, "service.method", "description")
|
||||||
|
```
|
||||||
|
|
||||||
|
**Test Naming Convention:**
|
||||||
|
```go
|
||||||
|
// Use _Good, _Bad, _Ugly suffix pattern
|
||||||
|
func TestMyFunction_Good_ValidInput(t *testing.T) { ... }
|
||||||
|
func TestMyFunction_Bad_InvalidInput(t *testing.T) { ... }
|
||||||
|
func TestMyFunction_Ugly_PanicCase(t *testing.T) { ... }
|
||||||
|
```
|
||||||
|
|
||||||
|
**i18n Strings:**
|
||||||
|
```go
|
||||||
|
// Use i18n package for user-facing strings
|
||||||
|
i18n.T("cmd.mycommand.description")
|
||||||
|
i18n.Label("status")
|
||||||
|
```
|
||||||
|
|
||||||
|
### Creating Sub-Issues
|
||||||
|
If the issue reveals additional work needed:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create a follow-up issue
|
||||||
|
gh issue create --repo host-uk/core \
|
||||||
|
--title "Follow-up: {description}" \
|
||||||
|
--body "Discovered while working on #{original_issue}
|
||||||
|
|
||||||
|
## Context
|
||||||
|
{explain what was found}
|
||||||
|
|
||||||
|
## Proposed Solution
|
||||||
|
{describe the approach}
|
||||||
|
|
||||||
|
## References
|
||||||
|
- Parent issue: #{original_issue}" \
|
||||||
|
--label "lang:go,follow-up"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 4: Push and Create PR
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Stage and commit
|
||||||
|
git add -A
|
||||||
|
git commit -m "feat({pkg}): {description}
|
||||||
|
|
||||||
|
{longer description if needed}
|
||||||
|
|
||||||
|
Closes #{issue_number}
|
||||||
|
|
||||||
|
Co-Authored-By: Claude <noreply@anthropic.com>"
|
||||||
|
|
||||||
|
# Push
|
||||||
|
git push -u origin feature/issue-{number}-{short-description}
|
||||||
|
|
||||||
|
# Create PR
|
||||||
|
gh pr create --repo host-uk/core \
|
||||||
|
--title "feat({pkg}): {description}" \
|
||||||
|
--body "$(cat <<'EOF'
|
||||||
|
## Summary
|
||||||
|
{Brief description of changes}
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
- {Change 1}
|
||||||
|
- {Change 2}
|
||||||
|
|
||||||
|
## Test Plan
|
||||||
|
- [ ] Unit tests added/updated
|
||||||
|
- [ ] `task test` passes
|
||||||
|
- [ ] `task lint` passes
|
||||||
|
- [ ] Manual testing completed
|
||||||
|
|
||||||
|
Closes #{issue_number}
|
||||||
|
|
||||||
|
---
|
||||||
|
Generated with Claude Code
|
||||||
|
EOF
|
||||||
|
)"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 5: Handle CodeRabbit Review
|
||||||
|
|
||||||
|
After pushing, CodeRabbit will automatically review. Track PR status:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check CodeRabbit status on latest commit
|
||||||
|
gh api repos/host-uk/core/commits/$(git rev-parse HEAD)/status --jq '.statuses[] | select(.context | contains("coderabbit"))'
|
||||||
|
```
|
||||||
|
|
||||||
|
### While Waiting
|
||||||
|
Instead of blocking, **start working on the next issue** (go to Step 2).
|
||||||
|
|
||||||
|
### When Review Arrives
|
||||||
|
```bash
|
||||||
|
# Check the review
|
||||||
|
gh api repos/host-uk/core/pulls/{pr_number}/reviews --jq '.[-1]'
|
||||||
|
|
||||||
|
# If "Actionable comments posted: N", fix them:
|
||||||
|
# 1. Read each comment
|
||||||
|
# 2. Make the fix
|
||||||
|
# 3. Commit with clear message
|
||||||
|
# 4. Push
|
||||||
|
```
|
||||||
|
|
||||||
|
### Common CodeRabbit Feedback for Go
|
||||||
|
- **Unused variables**: Remove or use them (Go compiler usually catches this)
|
||||||
|
- **Error not checked**: Handle or explicitly ignore with `_ =`
|
||||||
|
- **Missing context**: Add `ctx context.Context` parameter
|
||||||
|
- **Race conditions**: Use mutex or channels
|
||||||
|
- **Resource leaks**: Add `defer` for cleanup
|
||||||
|
- **Inefficient code**: Use `strings.Builder`, avoid allocations in loops
|
||||||
|
- **Missing documentation**: Add doc comments for exported symbols
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 6: Merge and Close
|
||||||
|
|
||||||
|
When CodeRabbit status shows "Review completed" with state "success":
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Merge the PR (squash merge)
|
||||||
|
gh pr merge {pr_number} --squash --repo host-uk/core
|
||||||
|
|
||||||
|
# The issue will auto-close if "Closes #N" was in PR body
|
||||||
|
# Otherwise, close manually:
|
||||||
|
gh issue close {number} --repo host-uk/core
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 7: Restart Loop
|
||||||
|
|
||||||
|
After merging:
|
||||||
|
|
||||||
|
1. Remove PR from `PENDING_PRS`
|
||||||
|
2. Check remaining pending PRs for reviews
|
||||||
|
3. Pick up next issue
|
||||||
|
4. **Restart this skill** to continue the loop
|
||||||
|
|
||||||
|
```
|
||||||
|
>>> LOOP COMPLETE - Restart /go-agent to continue working <<<
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Go Packages Reference (core CLI)
|
||||||
|
|
||||||
|
| Package | Purpose |
|
||||||
|
|---------|---------|
|
||||||
|
| `pkg/cli` | Command framework, styles, output |
|
||||||
|
| `pkg/errors` | Error handling with context |
|
||||||
|
| `pkg/i18n` | Internationalization |
|
||||||
|
| `pkg/qa` | QA commands (watch, review) |
|
||||||
|
| `pkg/setup` | Setup commands (github, bootstrap) |
|
||||||
|
| `pkg/dev` | Multi-repo dev workflow |
|
||||||
|
| `pkg/go` | Go tooling commands |
|
||||||
|
| `pkg/php` | PHP tooling commands |
|
||||||
|
| `pkg/build` | Build system |
|
||||||
|
| `pkg/release` | Release management |
|
||||||
|
| `pkg/sdk` | SDK generators |
|
||||||
|
| `pkg/container` | Container/VM management |
|
||||||
|
| `pkg/agentic` | Agent orchestration |
|
||||||
|
| `pkg/framework/core` | Core DI framework |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Task Commands Reference
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Testing
|
||||||
|
task test # Run all tests
|
||||||
|
task test:verbose # Verbose output
|
||||||
|
task test:run -- Name # Run specific test
|
||||||
|
task cov # Coverage report
|
||||||
|
|
||||||
|
# Code Quality
|
||||||
|
task fmt # Format code
|
||||||
|
task lint # Run linter
|
||||||
|
task qa # Full QA (fmt, vet, lint, test)
|
||||||
|
task qa:quick # Quick QA (no tests)
|
||||||
|
|
||||||
|
# Building
|
||||||
|
task cli:build # Build CLI to ./bin/core
|
||||||
|
task cli:install # Install to system
|
||||||
|
|
||||||
|
# Other
|
||||||
|
task mod:tidy # go mod tidy
|
||||||
|
task review # CodeRabbit review
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### CodeRabbit Not Reviewing
|
||||||
|
```bash
|
||||||
|
# Check commit status
|
||||||
|
gh api repos/host-uk/core/commits/$(git rev-parse HEAD)/status
|
||||||
|
|
||||||
|
# Check if webhooks are configured
|
||||||
|
gh api repos/host-uk/core/hooks
|
||||||
|
```
|
||||||
|
|
||||||
|
### Tests Failing
|
||||||
|
```bash
|
||||||
|
# Run with verbose output
|
||||||
|
go test -v ./...
|
||||||
|
|
||||||
|
# Run specific test
|
||||||
|
go test -run TestName ./pkg/...
|
||||||
|
|
||||||
|
# Run with race detector
|
||||||
|
go test -race ./...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Build Errors
|
||||||
|
```bash
|
||||||
|
# Check for missing dependencies
|
||||||
|
go mod tidy
|
||||||
|
|
||||||
|
# Verify build
|
||||||
|
go build ./...
|
||||||
|
|
||||||
|
# Check for vet issues
|
||||||
|
go vet ./...
|
||||||
|
```
|
||||||
|
|
||||||
|
### Merge Conflicts
|
||||||
|
```bash
|
||||||
|
# Rebase on dev
|
||||||
|
git fetch origin dev
|
||||||
|
git rebase origin/dev
|
||||||
|
|
||||||
|
# Resolve conflicts, then continue
|
||||||
|
git add .
|
||||||
|
git rebase --continue
|
||||||
|
git push --force-with-lease
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. **One issue per PR** - Keep changes focused
|
||||||
|
2. **Small commits** - Easier to review and revert
|
||||||
|
3. **Descriptive messages** - Help future maintainers
|
||||||
|
4. **Test coverage** - Don't decrease coverage
|
||||||
|
5. **Documentation** - Update if behavior changes
|
||||||
|
6. **Error context** - Use errors.E with service.method prefix
|
||||||
|
7. **i18n strings** - Add to en_GB.json for user-facing text
|
||||||
|
|
||||||
|
## Labels Reference
|
||||||
|
|
||||||
|
- `lang:go` - Go code changes
|
||||||
|
- `agent:ready` - Ready for AI agent pickup
|
||||||
|
- `good-first-issue` - Simple, well-defined tasks
|
||||||
|
- `priority:high` - Should be addressed soon
|
||||||
|
- `follow-up` - Created from another issue
|
||||||
|
- `needs:review` - Awaiting human review
|
||||||
|
- `bug` - Something isn't working
|
||||||
|
- `enhancement` - New feature or improvement
|
||||||
329
.core/plugin/skills/php-agent.md
Normal file
329
.core/plugin/skills/php-agent.md
Normal file
|
|
@ -0,0 +1,329 @@
|
||||||
|
# PHP Agent Skill
|
||||||
|
|
||||||
|
You are an autonomous PHP development agent working on the Host UK Laravel packages. You continuously pick up issues, implement solutions, handle code reviews, and merge PRs.
|
||||||
|
|
||||||
|
## Workflow Loop
|
||||||
|
|
||||||
|
This skill runs as a continuous loop:
|
||||||
|
|
||||||
|
```
|
||||||
|
1. CHECK PENDING PRs → Fix reviews if CodeRabbit commented
|
||||||
|
2. FIND ISSUE → Pick a PHP issue from host-uk org
|
||||||
|
3. IMPLEMENT → Create branch, code, test, push
|
||||||
|
4. HANDLE REVIEW → Wait for/fix CodeRabbit feedback
|
||||||
|
5. MERGE → Merge when approved
|
||||||
|
6. REPEAT → Start next task
|
||||||
|
```
|
||||||
|
|
||||||
|
## State Management
|
||||||
|
|
||||||
|
Track your work with these variables:
|
||||||
|
- `PENDING_PRS`: PRs waiting for CodeRabbit review
|
||||||
|
- `CURRENT_ISSUE`: Issue currently being worked on
|
||||||
|
- `CURRENT_BRANCH`: Branch for current work
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 1: Check Pending PRs
|
||||||
|
|
||||||
|
Before starting new work, check if any of your pending PRs have CodeRabbit reviews ready.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# List your open PRs across host-uk org
|
||||||
|
gh search prs --author=@me --state=open --owner=host-uk --json number,title,repository,url
|
||||||
|
|
||||||
|
# For each PR, check CodeRabbit status
|
||||||
|
gh api repos/host-uk/{repo}/commits/{sha}/status --jq '.statuses[] | select(.context | contains("coderabbit")) | {context, state, description}'
|
||||||
|
```
|
||||||
|
|
||||||
|
### If CodeRabbit review is complete:
|
||||||
|
- **Success (no issues)**: Merge the PR
|
||||||
|
- **Has comments**: Fix the issues, commit, push, continue to next task
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Check for new reviews
|
||||||
|
gh api repos/host-uk/{repo}/pulls/{pr_number}/reviews --jq 'sort_by(.submitted_at) | .[-1] | {author: .user.login, state: .state, body: .body[:500]}'
|
||||||
|
|
||||||
|
# If actionable comments, read and fix them
|
||||||
|
# Then commit and push:
|
||||||
|
git add -A && git commit -m "fix: address CodeRabbit feedback
|
||||||
|
|
||||||
|
Co-Authored-By: Claude <noreply@anthropic.com>"
|
||||||
|
git push
|
||||||
|
```
|
||||||
|
|
||||||
|
### Merging PRs
|
||||||
|
```bash
|
||||||
|
# When CodeRabbit approves (status: success), merge without admin
|
||||||
|
gh pr merge {pr_number} --squash --repo host-uk/{repo}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 2: Find an Issue
|
||||||
|
|
||||||
|
Search for PHP issues across the Host UK organization.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Find open issues labeled for PHP or in PHP repos
|
||||||
|
gh search issues --owner=host-uk --state=open --label="lang:php" --json number,title,repository,url --limit=10
|
||||||
|
|
||||||
|
# Or search across all repos for PHP-related issues
|
||||||
|
gh search issues --owner=host-uk --state=open --json number,title,repository,labels,body --limit=20
|
||||||
|
|
||||||
|
# Filter for PHP repos (core-php, core-tenant, core-admin, etc.)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Issue Selection Criteria
|
||||||
|
1. **Priority**: Issues with `priority:high` or `good-first-issue` labels
|
||||||
|
2. **Dependencies**: Check if issue depends on other incomplete work
|
||||||
|
3. **Scope**: Prefer issues that can be completed in one session
|
||||||
|
4. **Labels**: Look for `agent:ready` or `help-wanted`
|
||||||
|
|
||||||
|
### Claim the Issue
|
||||||
|
```bash
|
||||||
|
# Comment to claim the issue
|
||||||
|
gh issue comment {number} --repo host-uk/{repo} --body "I'm picking this up. Starting work now."
|
||||||
|
|
||||||
|
# Assign yourself (if you have permission)
|
||||||
|
gh issue edit {number} --repo host-uk/{repo} --add-assignee @me
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 3: Implement the Solution
|
||||||
|
|
||||||
|
### Setup Branch
|
||||||
|
```bash
|
||||||
|
# Navigate to the package
|
||||||
|
cd packages/{repo}
|
||||||
|
|
||||||
|
# Ensure you're on main/dev and up to date
|
||||||
|
git checkout dev && git pull
|
||||||
|
|
||||||
|
# Create feature branch
|
||||||
|
git checkout -b feature/issue-{number}-{short-description}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Development Workflow
|
||||||
|
1. **Read the code** - Understand the codebase structure
|
||||||
|
2. **Write tests first** - TDD approach when possible
|
||||||
|
3. **Implement the solution** - Follow Laravel/PHP best practices
|
||||||
|
4. **Run tests** - Ensure all tests pass
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Run tests
|
||||||
|
composer test
|
||||||
|
|
||||||
|
# Run linting
|
||||||
|
composer lint
|
||||||
|
|
||||||
|
# Run static analysis if available
|
||||||
|
composer analyse
|
||||||
|
```
|
||||||
|
|
||||||
|
### Code Quality Checklist
|
||||||
|
- [ ] Tests written and passing
|
||||||
|
- [ ] Code follows PSR-12 style
|
||||||
|
- [ ] No debugging code left in
|
||||||
|
- [ ] Documentation updated if needed
|
||||||
|
- [ ] Types/PHPDoc added for new methods
|
||||||
|
|
||||||
|
### Creating Sub-Issues
|
||||||
|
If the issue reveals additional work needed:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create a follow-up issue
|
||||||
|
gh issue create --repo host-uk/{repo} \
|
||||||
|
--title "Follow-up: {description}" \
|
||||||
|
--body "Discovered while working on #{original_issue}
|
||||||
|
|
||||||
|
## Context
|
||||||
|
{explain what was found}
|
||||||
|
|
||||||
|
## Proposed Solution
|
||||||
|
{describe the approach}
|
||||||
|
|
||||||
|
## References
|
||||||
|
- Parent issue: #{original_issue}" \
|
||||||
|
--label "lang:php,follow-up"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 4: Push and Create PR
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Stage and commit
|
||||||
|
git add -A
|
||||||
|
git commit -m "feat({scope}): {description}
|
||||||
|
|
||||||
|
{longer description if needed}
|
||||||
|
|
||||||
|
Closes #{issue_number}
|
||||||
|
|
||||||
|
Co-Authored-By: Claude <noreply@anthropic.com>"
|
||||||
|
|
||||||
|
# Push
|
||||||
|
git push -u origin feature/issue-{number}-{short-description}
|
||||||
|
|
||||||
|
# Create PR
|
||||||
|
gh pr create --repo host-uk/{repo} \
|
||||||
|
--title "feat({scope}): {description}" \
|
||||||
|
--body "$(cat <<'EOF'
|
||||||
|
## Summary
|
||||||
|
{Brief description of changes}
|
||||||
|
|
||||||
|
## Changes
|
||||||
|
- {Change 1}
|
||||||
|
- {Change 2}
|
||||||
|
|
||||||
|
## Test Plan
|
||||||
|
- [ ] Unit tests added/updated
|
||||||
|
- [ ] Manual testing completed
|
||||||
|
- [ ] CI passes
|
||||||
|
|
||||||
|
Closes #{issue_number}
|
||||||
|
|
||||||
|
---
|
||||||
|
Generated with Claude Code
|
||||||
|
EOF
|
||||||
|
)"
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 5: Handle CodeRabbit Review
|
||||||
|
|
||||||
|
After pushing, CodeRabbit will automatically review. Track PR status:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Add PR to pending list (note the PR number)
|
||||||
|
# PENDING_PRS+=({repo}:{pr_number})
|
||||||
|
|
||||||
|
# Check CodeRabbit status
|
||||||
|
gh api repos/host-uk/{repo}/commits/$(git rev-parse HEAD)/status --jq '.statuses[] | select(.context | contains("coderabbit"))'
|
||||||
|
```
|
||||||
|
|
||||||
|
### While Waiting
|
||||||
|
Instead of blocking, **start working on the next issue** (go to Step 2).
|
||||||
|
|
||||||
|
### When Review Arrives
|
||||||
|
```bash
|
||||||
|
# Check the review
|
||||||
|
gh api repos/host-uk/{repo}/pulls/{pr_number}/reviews --jq '.[-1]'
|
||||||
|
|
||||||
|
# If "Actionable comments posted: N", fix them:
|
||||||
|
# 1. Read each comment
|
||||||
|
# 2. Make the fix
|
||||||
|
# 3. Commit with clear message
|
||||||
|
# 4. Push
|
||||||
|
```
|
||||||
|
|
||||||
|
### Common CodeRabbit Feedback Patterns
|
||||||
|
- **Unused variables**: Remove or use them
|
||||||
|
- **Missing type hints**: Add return types, parameter types
|
||||||
|
- **Error handling**: Add try-catch or null checks
|
||||||
|
- **Test coverage**: Add missing test cases
|
||||||
|
- **Documentation**: Add PHPDoc blocks
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 6: Merge and Close
|
||||||
|
|
||||||
|
When CodeRabbit status shows "Review completed" with state "success":
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Merge the PR (squash merge)
|
||||||
|
gh pr merge {pr_number} --squash --repo host-uk/{repo}
|
||||||
|
|
||||||
|
# The issue will auto-close if "Closes #N" was in PR body
|
||||||
|
# Otherwise, close manually:
|
||||||
|
gh issue close {number} --repo host-uk/{repo}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Step 7: Restart Loop
|
||||||
|
|
||||||
|
After merging:
|
||||||
|
|
||||||
|
1. Remove PR from `PENDING_PRS`
|
||||||
|
2. Check remaining pending PRs for reviews
|
||||||
|
3. Pick up next issue
|
||||||
|
4. **Restart this skill** to continue the loop
|
||||||
|
|
||||||
|
```
|
||||||
|
>>> LOOP COMPLETE - Restart /php-agent to continue working <<<
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## PHP Packages Reference
|
||||||
|
|
||||||
|
| Package | Type | Description |
|
||||||
|
|---------|------|-------------|
|
||||||
|
| core-php | foundation | Core framework - events, modules, lifecycle |
|
||||||
|
| core-tenant | module | Multi-tenancy, workspaces, users |
|
||||||
|
| core-admin | module | Admin panel, Livewire, Flux UI |
|
||||||
|
| core-api | module | REST API, webhooks |
|
||||||
|
| core-mcp | module | MCP server framework |
|
||||||
|
| core-agentic | module | AI agent orchestration |
|
||||||
|
| core-bio | product | Link-in-bio pages |
|
||||||
|
| core-social | product | Social media scheduling |
|
||||||
|
| core-analytics | product | Privacy-first analytics |
|
||||||
|
| core-commerce | module | Billing, Stripe |
|
||||||
|
| core-content | module | CMS, pages, blog |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
### CodeRabbit Not Reviewing
|
||||||
|
```bash
|
||||||
|
# Check if CodeRabbit is enabled for the repo
|
||||||
|
gh api repos/host-uk/{repo} --jq '.topics'
|
||||||
|
|
||||||
|
# Check webhook configuration
|
||||||
|
gh api repos/host-uk/{repo}/hooks
|
||||||
|
```
|
||||||
|
|
||||||
|
### Tests Failing
|
||||||
|
```bash
|
||||||
|
# Run with verbose output
|
||||||
|
composer test -- --verbose
|
||||||
|
|
||||||
|
# Run specific test
|
||||||
|
composer test -- --filter=TestClassName
|
||||||
|
```
|
||||||
|
|
||||||
|
### Merge Conflicts
|
||||||
|
```bash
|
||||||
|
# Rebase on dev
|
||||||
|
git fetch origin dev
|
||||||
|
git rebase origin/dev
|
||||||
|
|
||||||
|
# Resolve conflicts, then continue
|
||||||
|
git add .
|
||||||
|
git rebase --continue
|
||||||
|
git push --force-with-lease
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Best Practices
|
||||||
|
|
||||||
|
1. **One issue per PR** - Keep changes focused
|
||||||
|
2. **Small commits** - Easier to review and revert
|
||||||
|
3. **Descriptive messages** - Help future maintainers
|
||||||
|
4. **Test coverage** - Don't decrease coverage
|
||||||
|
5. **Documentation** - Update if behavior changes
|
||||||
|
|
||||||
|
## Labels Reference
|
||||||
|
|
||||||
|
- `lang:php` - PHP code changes
|
||||||
|
- `agent:ready` - Ready for AI agent pickup
|
||||||
|
- `good-first-issue` - Simple, well-defined tasks
|
||||||
|
- `priority:high` - Should be addressed soon
|
||||||
|
- `follow-up` - Created from another issue
|
||||||
|
- `needs:review` - Awaiting human review
|
||||||
33
.devcontainer/devcontainer.json
Normal file
33
.devcontainer/devcontainer.json
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
{
|
||||||
|
"name": "Core Developer",
|
||||||
|
"image": "ghcr.io/host-uk/core-images:developer",
|
||||||
|
|
||||||
|
"workspaceMount": "source=${localWorkspaceFolder}/packages,target=/workspace,type=bind",
|
||||||
|
"workspaceFolder": "/workspace",
|
||||||
|
|
||||||
|
"mounts": [
|
||||||
|
"source=${localEnv:HOME}/.ssh,target=/root/.ssh,type=bind,readonly",
|
||||||
|
"source=${localEnv:HOME}/.gitconfig,target=/root/.gitconfig,type=bind,readonly",
|
||||||
|
"source=core-dev-home,target=/root,type=volume"
|
||||||
|
],
|
||||||
|
|
||||||
|
"containerEnv": {
|
||||||
|
"TERM": "xterm-256color",
|
||||||
|
"EDITOR": "nvim"
|
||||||
|
},
|
||||||
|
|
||||||
|
"customizations": {
|
||||||
|
"vscode": {
|
||||||
|
"extensions": [
|
||||||
|
"bmewburn.vscode-intelephense-client",
|
||||||
|
"golang.go",
|
||||||
|
"ms-python.python",
|
||||||
|
"rust-lang.rust-analyzer"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
"postCreateCommand": "echo 'Core Developer ready. Workspace: /workspace (packages/)'",
|
||||||
|
|
||||||
|
"remoteUser": "root"
|
||||||
|
}
|
||||||
10
.github/CODEOWNERS
vendored
Normal file
10
.github/CODEOWNERS
vendored
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
# Default owners for everything
|
||||||
|
* @host-uk/core-maintainers
|
||||||
|
|
||||||
|
# Scripts and CI
|
||||||
|
/scripts/ @host-uk/devops
|
||||||
|
/.github/ @host-uk/devops
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
*.md @host-uk/docs
|
||||||
|
/docs/ @host-uk/docs
|
||||||
51
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
51
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
|
|
@ -0,0 +1,51 @@
|
||||||
|
name: Bug Report
|
||||||
|
description: Report a problem with the developer workspace or scripts
|
||||||
|
title: "[Bug]: "
|
||||||
|
labels: ["bug", "triage"]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
Thanks for reporting! Please fill out the details below.
|
||||||
|
|
||||||
|
- type: dropdown
|
||||||
|
id: os
|
||||||
|
attributes:
|
||||||
|
label: Operating System
|
||||||
|
options:
|
||||||
|
- macOS
|
||||||
|
- Windows
|
||||||
|
- Linux (Ubuntu/Debian)
|
||||||
|
- Linux (Other)
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: script
|
||||||
|
attributes:
|
||||||
|
label: Script/Command
|
||||||
|
description: Which script or command failed?
|
||||||
|
placeholder: "e.g., make setup, install-deps.ps1, core doctor"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: description
|
||||||
|
attributes:
|
||||||
|
label: What happened?
|
||||||
|
description: Describe the issue
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: expected
|
||||||
|
attributes:
|
||||||
|
label: Expected behaviour
|
||||||
|
description: What should have happened?
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: logs
|
||||||
|
attributes:
|
||||||
|
label: Error output
|
||||||
|
description: Paste any error messages
|
||||||
|
render: shell
|
||||||
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
8
.github/ISSUE_TEMPLATE/config.yml
vendored
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
blank_issues_enabled: false
|
||||||
|
contact_links:
|
||||||
|
- name: Questions & Discussions
|
||||||
|
url: https://github.com/host-uk/core-devops/discussions
|
||||||
|
about: Ask questions and discuss ideas
|
||||||
|
- name: Security Issues
|
||||||
|
url: https://github.com/host-uk/core-devops/security/policy
|
||||||
|
about: Report security vulnerabilities privately
|
||||||
58
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
58
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
name: Feature Request
|
||||||
|
description: Suggest an improvement to the developer workspace
|
||||||
|
title: "[Feature]: "
|
||||||
|
labels: ["enhancement"]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
Thanks for the suggestion! Please describe your idea below.
|
||||||
|
|
||||||
|
- type: dropdown
|
||||||
|
id: area
|
||||||
|
attributes:
|
||||||
|
label: Area
|
||||||
|
options:
|
||||||
|
- Setup scripts (install-deps, install-core)
|
||||||
|
- Core CLI commands
|
||||||
|
- Documentation
|
||||||
|
- IDE configuration
|
||||||
|
- CI/CD workflows
|
||||||
|
- Other
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: problem
|
||||||
|
attributes:
|
||||||
|
label: Problem or use case
|
||||||
|
description: What problem does this solve?
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: solution
|
||||||
|
attributes:
|
||||||
|
label: Proposed solution
|
||||||
|
description: How would you like it to work?
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: alternatives
|
||||||
|
attributes:
|
||||||
|
label: Alternatives considered
|
||||||
|
description: Any other approaches you've thought about?
|
||||||
|
|
||||||
|
- type: dropdown
|
||||||
|
id: complexity
|
||||||
|
attributes:
|
||||||
|
label: Estimated complexity
|
||||||
|
description: How much work do you think this requires?
|
||||||
|
options:
|
||||||
|
- "Small - Quick fix, single file, < 1 hour"
|
||||||
|
- "Medium - Multiple files, few hours to a day"
|
||||||
|
- "Large - Significant changes, multiple days"
|
||||||
|
- "Unknown - Not sure"
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
25
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
25
.github/PULL_REQUEST_TEMPLATE.md
vendored
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
## Summary
|
||||||
|
|
||||||
|
<!-- Brief description of changes -->
|
||||||
|
|
||||||
|
## Type of change
|
||||||
|
|
||||||
|
- [ ] Bug fix
|
||||||
|
- [ ] New feature
|
||||||
|
- [ ] Documentation
|
||||||
|
- [ ] CI/CD improvement
|
||||||
|
- [ ] Other: <!-- describe -->
|
||||||
|
|
||||||
|
## Checklist
|
||||||
|
|
||||||
|
- [ ] Scripts tested on target OS (macOS/Windows/Linux)
|
||||||
|
- [ ] Documentation updated if needed
|
||||||
|
- [ ] No secrets or credentials in code
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
<!-- How did you test these changes? -->
|
||||||
|
|
||||||
|
## Related issues
|
||||||
|
|
||||||
|
<!-- Link any related issues: Fixes #123, Relates to #456 -->
|
||||||
24
.github/dependabot.yml
vendored
Normal file
24
.github/dependabot.yml
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
version: 2
|
||||||
|
updates:
|
||||||
|
# GitHub Actions
|
||||||
|
- package-ecosystem: "github-actions"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
|
commit-message:
|
||||||
|
prefix: "ci(deps)"
|
||||||
|
labels:
|
||||||
|
- "dependencies"
|
||||||
|
- "github-actions"
|
||||||
|
|
||||||
|
# Go modules (for core CLI when built locally)
|
||||||
|
- package-ecosystem: "gomod"
|
||||||
|
directory: "/"
|
||||||
|
schedule:
|
||||||
|
interval: "weekly"
|
||||||
|
commit-message:
|
||||||
|
prefix: "chore(deps)"
|
||||||
|
labels:
|
||||||
|
- "dependencies"
|
||||||
|
- "go"
|
||||||
|
open-pull-requests-limit: 5
|
||||||
23
.github/workflow-templates/security-docker.yml
vendored
Normal file
23
.github/workflow-templates/security-docker.yml
vendored
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
name: Dockerfile Lint
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [dev, main]
|
||||||
|
paths: ['**/Dockerfile*', '**.dockerfile']
|
||||||
|
pull_request:
|
||||||
|
branches: [dev, main]
|
||||||
|
paths: ['**/Dockerfile*', '**.dockerfile']
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
hadolint:
|
||||||
|
name: Hadolint
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Run Hadolint
|
||||||
|
uses: hadolint/hadolint-action@v3.1.0
|
||||||
|
with:
|
||||||
|
recursive: true
|
||||||
|
failure-threshold: warning
|
||||||
50
.github/workflow-templates/security-php.yml
vendored
Normal file
50
.github/workflow-templates/security-php.yml
vendored
Normal file
|
|
@ -0,0 +1,50 @@
|
||||||
|
name: PHP Security
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [dev, main]
|
||||||
|
pull_request:
|
||||||
|
branches: [dev, main]
|
||||||
|
schedule:
|
||||||
|
- cron: '0 6 * * 1'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
security-events: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
phpstan:
|
||||||
|
name: PHPStan
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Setup PHP
|
||||||
|
uses: shivammathur/setup-php@v2
|
||||||
|
with:
|
||||||
|
php-version: '8.3'
|
||||||
|
coverage: none
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: composer install --no-interaction --prefer-dist
|
||||||
|
|
||||||
|
- name: Run PHPStan
|
||||||
|
run: vendor/bin/phpstan analyse --error-format=github || true
|
||||||
|
|
||||||
|
semgrep:
|
||||||
|
name: Semgrep SAST
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: semgrep/semgrep
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Run Semgrep
|
||||||
|
run: semgrep scan --config auto --sarif --output results.sarif || true
|
||||||
|
|
||||||
|
- name: Upload SARIF
|
||||||
|
uses: github/codeql-action/upload-sarif@v3
|
||||||
|
with:
|
||||||
|
sarif_file: results.sarif
|
||||||
|
if: always()
|
||||||
24
.github/workflow-templates/security-shell.yml
vendored
Normal file
24
.github/workflow-templates/security-shell.yml
vendored
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
name: Shell Lint
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [dev, main]
|
||||||
|
paths: ['**.sh', '**.bash', 'scripts/**']
|
||||||
|
pull_request:
|
||||||
|
branches: [dev, main]
|
||||||
|
paths: ['**.sh', '**.bash', 'scripts/**']
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
shellcheck:
|
||||||
|
name: ShellCheck
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Run ShellCheck
|
||||||
|
uses: ludeeus/action-shellcheck@master
|
||||||
|
with:
|
||||||
|
severity: warning
|
||||||
|
scandir: '.'
|
||||||
|
format: gcc
|
||||||
126
.github/workflows/ai-worker.yml
vendored
Normal file
126
.github/workflows/ai-worker.yml
vendored
Normal file
|
|
@ -0,0 +1,126 @@
|
||||||
|
name: AI Worker (Free Tier)
|
||||||
|
|
||||||
|
# Runs on contributor's fork - uses THEIR API allowances
|
||||||
|
# Gemini 2.0 Flash: 1500 req/day free
|
||||||
|
# Jules: Available to all GitHub users
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize]
|
||||||
|
issues:
|
||||||
|
types: [labeled]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: write
|
||||||
|
pull-requests: write
|
||||||
|
issues: write
|
||||||
|
|
||||||
|
env:
|
||||||
|
# Contributors set their own GEMINI_API_KEY in fork secrets
|
||||||
|
# Free tier: 1500 requests/day, 1M tokens/min
|
||||||
|
GEMINI_API_KEY: ${{ secrets.GEMINI_API_KEY }}
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# Analyze PR with Gemini (contributor's free tier)
|
||||||
|
gemini-review:
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Get diff
|
||||||
|
id: diff
|
||||||
|
run: |
|
||||||
|
DIFF=$(git diff origin/${{ github.base_ref }}...HEAD | head -c 50000)
|
||||||
|
echo "diff<<EOFMARKER" >> $GITHUB_OUTPUT
|
||||||
|
echo "$DIFF" >> $GITHUB_OUTPUT
|
||||||
|
echo "EOFMARKER" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Gemini Analysis
|
||||||
|
if: env.GEMINI_API_KEY != ''
|
||||||
|
id: gemini
|
||||||
|
run: |
|
||||||
|
# Call Gemini 2.0 Flash (free tier)
|
||||||
|
RESPONSE=$(curl -s "https://generativelanguage.googleapis.com/v1beta/models/gemini-2.0-flash-exp:generateContent?key=$GEMINI_API_KEY" \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d @- << 'PAYLOAD'
|
||||||
|
{
|
||||||
|
"contents": [{
|
||||||
|
"parts": [{
|
||||||
|
"text": "Review this code diff. Be concise. List: 1) Security issues 2) Bugs 3) Improvements. If none, say 'LGTM'.\n\nDiff:\n${{ steps.diff.outputs.diff }}"
|
||||||
|
}]
|
||||||
|
}],
|
||||||
|
"generationConfig": {
|
||||||
|
"temperature": 0.2,
|
||||||
|
"maxOutputTokens": 1000
|
||||||
|
}
|
||||||
|
}
|
||||||
|
PAYLOAD
|
||||||
|
)
|
||||||
|
|
||||||
|
# Extract text from response
|
||||||
|
REVIEW=$(echo "$RESPONSE" | jq -r '.candidates[0].content.parts[0].text // "Analysis failed"')
|
||||||
|
echo "review<<EOFMARKER" >> $GITHUB_OUTPUT
|
||||||
|
echo "$REVIEW" >> $GITHUB_OUTPUT
|
||||||
|
echo "EOFMARKER" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Post Gemini review
|
||||||
|
if: steps.gemini.outputs.review != ''
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const review = `${{ steps.gemini.outputs.review }}`;
|
||||||
|
await github.rest.issues.createComment({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: context.issue.number,
|
||||||
|
body: `## 🤖 Gemini Analysis (Free Tier)\n\n${review}\n\n---\n_Powered by contributor's Gemini API allowance (1500 req/day free)_`
|
||||||
|
});
|
||||||
|
|
||||||
|
# Trigger Jules to fix issues (contributor's Copilot allowance)
|
||||||
|
trigger-jules:
|
||||||
|
if: github.event_name == 'issues' && github.event.label.name == 'agent:ready'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Check Jules eligibility
|
||||||
|
id: check
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
// Check if this repo has Copilot coding agent enabled
|
||||||
|
const issue = context.payload.issue;
|
||||||
|
|
||||||
|
console.log(`Issue #${issue.number}: ${issue.title}`);
|
||||||
|
console.log(`Labels: ${issue.labels.map(l => l.name).join(', ')}`);
|
||||||
|
|
||||||
|
// Jules can be assigned to issues with specific labels
|
||||||
|
const hasAgentic = issue.labels.some(l => l.name === 'agentic');
|
||||||
|
|
||||||
|
return { eligible: hasAgentic, issueNumber: issue.number };
|
||||||
|
|
||||||
|
- name: Assign to Jules
|
||||||
|
if: steps.check.outputs.result != ''
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
// Trigger Jules by adding the copilot label
|
||||||
|
// Jules will pick up the issue and create a PR
|
||||||
|
try {
|
||||||
|
await github.rest.issues.addLabels({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: context.payload.issue.number,
|
||||||
|
labels: ['copilot'] // This triggers Jules/Copilot coding agent
|
||||||
|
});
|
||||||
|
|
||||||
|
await github.rest.issues.createComment({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: context.payload.issue.number,
|
||||||
|
body: `## 🤖 Jules Activated\n\nThis issue has been assigned to GitHub Copilot coding agent (Jules).\n\nJules will:\n1. Analyze the issue\n2. Create a solution\n3. Open a PR with the fix\n\n_Using contributor's Copilot allowance_ 🆓`
|
||||||
|
});
|
||||||
|
} catch (e) {
|
||||||
|
console.log('Could not assign to Jules:', e.message);
|
||||||
|
}
|
||||||
110
.github/workflows/auto-label.yml
vendored
Normal file
110
.github/workflows/auto-label.yml
vendored
Normal file
|
|
@ -0,0 +1,110 @@
|
||||||
|
name: Auto Label Issues
|
||||||
|
|
||||||
|
on:
|
||||||
|
issues:
|
||||||
|
types: [opened, edited]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
issues: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
label:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Auto-label based on content
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const issue = context.payload.issue;
|
||||||
|
const title = issue.title.toLowerCase();
|
||||||
|
const body = (issue.body || '').toLowerCase();
|
||||||
|
const content = title + ' ' + body;
|
||||||
|
|
||||||
|
const labelsToAdd = [];
|
||||||
|
|
||||||
|
// Type labels based on title prefix
|
||||||
|
if (title.includes('[bug]')) {
|
||||||
|
labelsToAdd.push('bug');
|
||||||
|
} else if (title.includes('[feature]') || title.includes('feat(') || title.includes('feat:')) {
|
||||||
|
labelsToAdd.push('enhancement');
|
||||||
|
} else if (title.includes('[docs]') || title.includes('docs(') || title.includes('docs:')) {
|
||||||
|
labelsToAdd.push('documentation');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Project labels based on content
|
||||||
|
if (content.includes('core dev') || content.includes('core work') || content.includes('core commit') || content.includes('core push')) {
|
||||||
|
labelsToAdd.push('project:core-cli');
|
||||||
|
}
|
||||||
|
if (content.includes('core php') || content.includes('composer') || content.includes('pest') || content.includes('phpstan')) {
|
||||||
|
labelsToAdd.push('project:core-php');
|
||||||
|
}
|
||||||
|
if (content.includes('setup') || content.includes('install') || content.includes('makefile')) {
|
||||||
|
labelsToAdd.push('project:workstation');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Priority detection
|
||||||
|
if (content.includes('critical') || content.includes('urgent') || content.includes('breaking')) {
|
||||||
|
labelsToAdd.push('priority:high');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Agent labels
|
||||||
|
if (content.includes('agent') || content.includes('ai ') || content.includes('claude') || content.includes('agentic')) {
|
||||||
|
labelsToAdd.push('agentic');
|
||||||
|
}
|
||||||
|
|
||||||
|
// Complexity - from template dropdown or heuristics
|
||||||
|
if (body.includes('small - quick fix')) {
|
||||||
|
labelsToAdd.push('complexity:small');
|
||||||
|
labelsToAdd.push('good first issue');
|
||||||
|
} else if (body.includes('medium - multiple files')) {
|
||||||
|
labelsToAdd.push('complexity:medium');
|
||||||
|
} else if (body.includes('large - significant')) {
|
||||||
|
labelsToAdd.push('complexity:large');
|
||||||
|
} else if (!body.includes('unknown - not sure')) {
|
||||||
|
// Heuristic complexity detection
|
||||||
|
const checklistCount = (body.match(/- \[ \]/g) || []).length;
|
||||||
|
const codeBlocks = (body.match(/```/g) || []).length / 2;
|
||||||
|
const sections = (body.match(/^##/gm) || []).length;
|
||||||
|
const fileRefs = (body.match(/\.(go|php|js|ts|yml|yaml|json|md)\b/g) || []).length;
|
||||||
|
|
||||||
|
const complexKeywords = ['refactor', 'rewrite', 'migration', 'breaking change', 'across repos', 'architecture'];
|
||||||
|
const simpleKeywords = ['simple', 'quick fix', 'typo', 'minor', 'trivial'];
|
||||||
|
|
||||||
|
const hasComplexKeyword = complexKeywords.some(k => content.includes(k));
|
||||||
|
const hasSimpleKeyword = simpleKeywords.some(k => content.includes(k));
|
||||||
|
|
||||||
|
let score = checklistCount * 2 + codeBlocks + sections + fileRefs;
|
||||||
|
score += hasComplexKeyword ? 5 : 0;
|
||||||
|
score -= hasSimpleKeyword ? 3 : 0;
|
||||||
|
|
||||||
|
if (hasSimpleKeyword || score <= 2) {
|
||||||
|
labelsToAdd.push('complexity:small');
|
||||||
|
labelsToAdd.push('good first issue');
|
||||||
|
} else if (score <= 6) {
|
||||||
|
labelsToAdd.push('complexity:medium');
|
||||||
|
} else {
|
||||||
|
labelsToAdd.push('complexity:large');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply labels if any detected
|
||||||
|
if (labelsToAdd.length > 0) {
|
||||||
|
// Filter to only existing labels
|
||||||
|
const existingLabels = await github.rest.issues.listLabelsForRepo({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
per_page: 100
|
||||||
|
});
|
||||||
|
const validLabels = existingLabels.data.map(l => l.name);
|
||||||
|
const filteredLabels = labelsToAdd.filter(l => validLabels.includes(l));
|
||||||
|
|
||||||
|
if (filteredLabels.length > 0) {
|
||||||
|
await github.rest.issues.addLabels({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: issue.number,
|
||||||
|
labels: filteredLabels
|
||||||
|
});
|
||||||
|
console.log(`Added labels: ${filteredLabels.join(', ')}`);
|
||||||
|
}
|
||||||
|
}
|
||||||
36
.github/workflows/codeql.yml
vendored
Normal file
36
.github/workflows/codeql.yml
vendored
Normal file
|
|
@ -0,0 +1,36 @@
|
||||||
|
name: CodeQL
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [dev, main]
|
||||||
|
pull_request:
|
||||||
|
branches: [dev, main]
|
||||||
|
schedule:
|
||||||
|
- cron: "0 6 * * 1"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
analyze:
|
||||||
|
name: Analyze
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
actions: read
|
||||||
|
contents: read
|
||||||
|
security-events: write
|
||||||
|
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Initialize CodeQL
|
||||||
|
uses: github/codeql-action/init@v3
|
||||||
|
with:
|
||||||
|
languages: javascript
|
||||||
|
|
||||||
|
- name: Autobuild
|
||||||
|
uses: github/codeql-action/autobuild@v3
|
||||||
|
|
||||||
|
- name: Perform CodeQL Analysis
|
||||||
|
uses: github/codeql-action/analyze@v3
|
||||||
|
with:
|
||||||
|
category: "/language:javascript"
|
||||||
|
|
||||||
57
.github/workflows/contributor-ci.yml
vendored
Normal file
57
.github/workflows/contributor-ci.yml
vendored
Normal file
|
|
@ -0,0 +1,57 @@
|
||||||
|
name: Contributor CI
|
||||||
|
|
||||||
|
# Runs on fork's compute allowance (Microsoft/GitHub free tier)
|
||||||
|
# Heavy analysis happens here, not on upstream
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches-ignore: [main, dev] # Only feature branches (forks)
|
||||||
|
pull_request:
|
||||||
|
branches: [main, dev]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# This runs on CONTRIBUTOR'S allowance
|
||||||
|
analyze:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Run analysis
|
||||||
|
run: |
|
||||||
|
echo "## 🔍 Contributor Analysis" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "This CI runs on your fork's GitHub Actions allowance." >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
# Add your heavy analysis here - it's FREE for contributors
|
||||||
|
# - CodeQL scanning
|
||||||
|
# - Dependency analysis
|
||||||
|
# - AI-powered code review (if using Copilot)
|
||||||
|
# - Full test suite
|
||||||
|
|
||||||
|
- name: Lint
|
||||||
|
run: |
|
||||||
|
# Linting on contributor's compute
|
||||||
|
echo "Running lint..."
|
||||||
|
|
||||||
|
- name: Security scan
|
||||||
|
run: |
|
||||||
|
# Security scanning on contributor's compute
|
||||||
|
echo "Running security scan..."
|
||||||
|
|
||||||
|
# AI-powered analysis (uses contributor's Copilot/AI allowance)
|
||||||
|
ai-review:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: AI Analysis Placeholder
|
||||||
|
run: |
|
||||||
|
echo "## 🤖 AI Analysis" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "This would run AI analysis using:" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "- Contributor's Copilot allowance" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "- GitHub's free AI features" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "- Any AI APIs the contributor has configured" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "Upstream repo pays nothing. 💰" >> $GITHUB_STEP_SUMMARY
|
||||||
58
.github/workflows/docs.yml
vendored
Normal file
58
.github/workflows/docs.yml
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
name: Deploy Docs
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [dev, main]
|
||||||
|
paths:
|
||||||
|
- 'doc/**'
|
||||||
|
- '.vitepress/**'
|
||||||
|
- 'package.json'
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pages: write
|
||||||
|
id-token: write
|
||||||
|
|
||||||
|
concurrency:
|
||||||
|
group: pages
|
||||||
|
cancel-in-progress: false
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
build:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Setup Node
|
||||||
|
uses: actions/setup-node@v4
|
||||||
|
with:
|
||||||
|
node-version: 20
|
||||||
|
|
||||||
|
- name: Setup Pages
|
||||||
|
uses: actions/configure-pages@v4
|
||||||
|
|
||||||
|
- name: Install dependencies
|
||||||
|
run: npm install
|
||||||
|
|
||||||
|
- name: Build with VitePress
|
||||||
|
run: npm run docs:build
|
||||||
|
|
||||||
|
- name: Upload artifact
|
||||||
|
uses: actions/upload-pages-artifact@v3
|
||||||
|
with:
|
||||||
|
path: .vitepress/dist
|
||||||
|
|
||||||
|
deploy:
|
||||||
|
environment:
|
||||||
|
name: github-pages
|
||||||
|
url: ${{ steps.deployment.outputs.page_url }}
|
||||||
|
needs: build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Deploy to GitHub Pages
|
||||||
|
id: deployment
|
||||||
|
uses: actions/deploy-pages@v4
|
||||||
120
.github/workflows/fork-ai-triage.yml
vendored
Normal file
120
.github/workflows/fork-ai-triage.yml
vendored
Normal file
|
|
@ -0,0 +1,120 @@
|
||||||
|
name: AI Triage (Fork Compute)
|
||||||
|
|
||||||
|
# Strategy: Heavy AI analysis runs on contributor's fork
|
||||||
|
# They get free GitHub Copilot / Actions minutes
|
||||||
|
# We only do lightweight verification
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize, reopened]
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# Runs on contributor's GitHub Actions allowance
|
||||||
|
ai-triage:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Get changed files
|
||||||
|
id: changes
|
||||||
|
run: |
|
||||||
|
FILES=$(git diff --name-only origin/${{ github.base_ref }}...HEAD | head -50)
|
||||||
|
echo "files<<EOF" >> $GITHUB_OUTPUT
|
||||||
|
echo "$FILES" >> $GITHUB_OUTPUT
|
||||||
|
echo "EOF" >> $GITHUB_OUTPUT
|
||||||
|
echo "count=$(echo "$FILES" | wc -l)" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Categorize changes
|
||||||
|
id: categorize
|
||||||
|
run: |
|
||||||
|
# Determine what type of changes (runs on fork's compute)
|
||||||
|
PHP_COUNT=$(git diff --name-only origin/${{ github.base_ref }}...HEAD | grep -c '\.php$' || echo 0)
|
||||||
|
GO_COUNT=$(git diff --name-only origin/${{ github.base_ref }}...HEAD | grep -c '\.go$' || echo 0)
|
||||||
|
JS_COUNT=$(git diff --name-only origin/${{ github.base_ref }}...HEAD | grep -cE '\.(js|ts)$' || echo 0)
|
||||||
|
DOC_COUNT=$(git diff --name-only origin/${{ github.base_ref }}...HEAD | grep -cE '\.(md|txt)$' || echo 0)
|
||||||
|
|
||||||
|
echo "php=$PHP_COUNT" >> $GITHUB_OUTPUT
|
||||||
|
echo "go=$GO_COUNT" >> $GITHUB_OUTPUT
|
||||||
|
echo "js=$JS_COUNT" >> $GITHUB_OUTPUT
|
||||||
|
echo "docs=$DOC_COUNT" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
# Suggest labels
|
||||||
|
LABELS=""
|
||||||
|
[ "$PHP_COUNT" -gt 0 ] && LABELS="$LABELS,lang:php"
|
||||||
|
[ "$GO_COUNT" -gt 0 ] && LABELS="$LABELS,lang:go"
|
||||||
|
[ "$JS_COUNT" -gt 0 ] && LABELS="$LABELS,lang:js"
|
||||||
|
[ "$DOC_COUNT" -gt 0 ] && LABELS="$LABELS,type:docs"
|
||||||
|
|
||||||
|
echo "labels=${LABELS#,}" >> $GITHUB_OUTPUT
|
||||||
|
|
||||||
|
- name: Security quick scan
|
||||||
|
run: |
|
||||||
|
# Quick security checks (contributor's compute)
|
||||||
|
echo "Checking for secrets..."
|
||||||
|
|
||||||
|
# Check for common secret patterns
|
||||||
|
if git diff origin/${{ github.base_ref }}...HEAD | grep -iE '(api_key|secret|password|token)\s*[:=]' | grep -v 'example\|placeholder\|xxx'; then
|
||||||
|
echo "::warning::Possible secrets detected in diff"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Check for .env files
|
||||||
|
if git diff --name-only origin/${{ github.base_ref }}...HEAD | grep -E '\.env$'; then
|
||||||
|
echo "::error::Environment file changes detected - review carefully"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Generate triage summary
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const changes = `${{ steps.changes.outputs.files }}`.split('\n').filter(f => f);
|
||||||
|
const labels = '${{ steps.categorize.outputs.labels }}'.split(',').filter(l => l);
|
||||||
|
|
||||||
|
const summary = `## 🤖 AI Triage Summary
|
||||||
|
|
||||||
|
**Files changed:** ${changes.length}
|
||||||
|
**Languages detected:** ${labels.filter(l => l.startsWith('lang:')).map(l => l.replace('lang:', '')).join(', ') || 'none'}
|
||||||
|
|
||||||
|
### Suggested labels
|
||||||
|
${labels.map(l => '`' + l + '`').join(' ') || '_No suggestions_'}
|
||||||
|
|
||||||
|
### Changed files
|
||||||
|
<details>
|
||||||
|
<summary>View ${changes.length} files</summary>
|
||||||
|
|
||||||
|
\`\`\`
|
||||||
|
${changes.join('\n')}
|
||||||
|
\`\`\`
|
||||||
|
</details>
|
||||||
|
|
||||||
|
---
|
||||||
|
_This analysis ran on the contributor's GitHub Actions allowance._ 🆓
|
||||||
|
`;
|
||||||
|
|
||||||
|
await github.rest.issues.createComment({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: context.issue.number,
|
||||||
|
body: summary
|
||||||
|
});
|
||||||
|
|
||||||
|
- name: Apply suggested labels
|
||||||
|
if: steps.categorize.outputs.labels != ''
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
continue-on-error: true
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const labels = '${{ steps.categorize.outputs.labels }}'.split(',').filter(l => l);
|
||||||
|
if (labels.length > 0) {
|
||||||
|
await github.rest.issues.addLabels({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: context.issue.number,
|
||||||
|
labels: labels
|
||||||
|
});
|
||||||
|
}
|
||||||
37
.github/workflows/fork-pr-analysis.yml
vendored
Normal file
37
.github/workflows/fork-pr-analysis.yml
vendored
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
name: PR Analysis (Fork)
|
||||||
|
|
||||||
|
# This workflow runs on the FORK's resources, not ours
|
||||||
|
# Contributors get free GitHub Actions minutes
|
||||||
|
# Microsoft/GitHub subsidizes the compute
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request_target:
|
||||||
|
types: [opened, synchronize]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# Lightweight check on our side - just verify the fork did the work
|
||||||
|
verify-fork-ci:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Check fork CI status
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const { data: checks } = await github.rest.checks.listForRef({
|
||||||
|
owner: context.payload.pull_request.head.repo.owner.login,
|
||||||
|
repo: context.payload.pull_request.head.repo.name,
|
||||||
|
ref: context.payload.pull_request.head.sha
|
||||||
|
});
|
||||||
|
|
||||||
|
const passed = checks.check_runs.filter(c => c.conclusion === 'success');
|
||||||
|
const failed = checks.check_runs.filter(c => c.conclusion === 'failure');
|
||||||
|
|
||||||
|
console.log(`Fork CI: ${passed.length} passed, ${failed.length} failed`);
|
||||||
|
|
||||||
|
if (failed.length > 0) {
|
||||||
|
core.setFailed('Fork CI has failures - contributor must fix on their fork');
|
||||||
|
}
|
||||||
|
|
||||||
|
---
|
||||||
|
# This file goes in the TEMPLATE so forks inherit it
|
||||||
|
# The heavy work runs on contributor's GitHub Actions allowance
|
||||||
145
.github/workflows/free-tier-ai.yml
vendored
Normal file
145
.github/workflows/free-tier-ai.yml
vendored
Normal file
|
|
@ -0,0 +1,145 @@
|
||||||
|
name: Free Tier AI Analysis
|
||||||
|
|
||||||
|
on:
|
||||||
|
pull_request:
|
||||||
|
types: [opened, synchronize]
|
||||||
|
issues:
|
||||||
|
types: [opened, labeled]
|
||||||
|
workflow_dispatch:
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
pull-requests: write
|
||||||
|
issues: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# Groq - 14,400 requests/day FREE (Llama 3, Mixtral)
|
||||||
|
groq-analysis:
|
||||||
|
if: github.event_name == 'pull_request'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Get diff
|
||||||
|
id: diff
|
||||||
|
run: |
|
||||||
|
git diff origin/${{ github.base_ref }}...HEAD > /tmp/diff.txt
|
||||||
|
head -c 30000 /tmp/diff.txt > /tmp/diff_truncated.txt
|
||||||
|
|
||||||
|
- name: Groq Analysis
|
||||||
|
if: env.GROQ_API_KEY != ''
|
||||||
|
env:
|
||||||
|
GROQ_API_KEY: ${{ secrets.GROQ_API_KEY }}
|
||||||
|
run: |
|
||||||
|
# Groq is FAST and FREE (14,400 req/day)
|
||||||
|
DIFF=$(cat /tmp/diff_truncated.txt | jq -Rs .)
|
||||||
|
|
||||||
|
curl -s https://api.groq.com/openai/v1/chat/completions \
|
||||||
|
-H "Authorization: Bearer $GROQ_API_KEY" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{
|
||||||
|
\"model\": \"llama-3.3-70b-versatile\",
|
||||||
|
\"messages\": [{
|
||||||
|
\"role\": \"user\",
|
||||||
|
\"content\": \"Review this diff for security issues, bugs, and code smells. Be very concise. Output as: SECURITY: x issues, BUGS: x issues, SMELLS: x issues. Then list critical items only.\n\nDiff:\n${DIFF}\"
|
||||||
|
}],
|
||||||
|
\"temperature\": 0.1,
|
||||||
|
\"max_tokens\": 500
|
||||||
|
}" | jq -r '.choices[0].message.content' > /tmp/groq_review.txt
|
||||||
|
|
||||||
|
cat /tmp/groq_review.txt
|
||||||
|
|
||||||
|
# Mistral - Free tier available
|
||||||
|
mistral-analysis:
|
||||||
|
if: github.event_name == 'pull_request' && vars.MISTRAL_API_KEY != ''
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
continue-on-error: true
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
- name: Mistral Code Review
|
||||||
|
env:
|
||||||
|
MISTRAL_API_KEY: ${{ secrets.MISTRAL_API_KEY }}
|
||||||
|
run: |
|
||||||
|
echo "Mistral analysis would run here"
|
||||||
|
# Similar pattern to Groq
|
||||||
|
|
||||||
|
# Cohere - 1000 req/month free (good for classification)
|
||||||
|
cohere-classify:
|
||||||
|
if: github.event_name == 'issues'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
continue-on-error: true
|
||||||
|
steps:
|
||||||
|
- name: Classify Issue
|
||||||
|
if: env.COHERE_API_KEY != ''
|
||||||
|
env:
|
||||||
|
COHERE_API_KEY: ${{ secrets.COHERE_API_KEY }}
|
||||||
|
run: |
|
||||||
|
# Use Cohere to classify issue type/priority
|
||||||
|
TITLE="${{ github.event.issue.title }}"
|
||||||
|
BODY="${{ github.event.issue.body }}"
|
||||||
|
|
||||||
|
curl -s https://api.cohere.ai/v1/classify \
|
||||||
|
-H "Authorization: Bearer $COHERE_API_KEY" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d "{
|
||||||
|
\"inputs\": [\"$TITLE\"],
|
||||||
|
\"examples\": [
|
||||||
|
{\"text\": \"App crashes on login\", \"label\": \"bug\"},
|
||||||
|
{\"text\": \"Add dark mode\", \"label\": \"feature\"},
|
||||||
|
{\"text\": \"SQL injection in auth\", \"label\": \"security\"},
|
||||||
|
{\"text\": \"Slow page load\", \"label\": \"performance\"}
|
||||||
|
]
|
||||||
|
}" | jq '.classifications[0].prediction'
|
||||||
|
|
||||||
|
# Cloudflare Workers AI - 10,000 neurons/day FREE
|
||||||
|
cloudflare-ai:
|
||||||
|
if: github.event_name == 'pull_request' && vars.CF_ACCOUNT_ID != ''
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
continue-on-error: true
|
||||||
|
steps:
|
||||||
|
- name: Cloudflare AI Analysis
|
||||||
|
env:
|
||||||
|
CF_API_TOKEN: ${{ secrets.CF_API_TOKEN }}
|
||||||
|
CF_ACCOUNT_ID: ${{ vars.CF_ACCOUNT_ID }}
|
||||||
|
run: |
|
||||||
|
# Cloudflare Workers AI - runs at the edge
|
||||||
|
echo "Cloudflare AI analysis would run here"
|
||||||
|
# @cf/meta/llama-3-8b-instruct is free
|
||||||
|
|
||||||
|
# Aggregate results and create summary
|
||||||
|
aggregate:
|
||||||
|
needs: [groq-analysis]
|
||||||
|
if: always() && github.event_name == 'pull_request'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Create Summary
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const summary = `## 🤖 Free Tier AI Analysis
|
||||||
|
|
||||||
|
Multiple AI services analyzed this PR:
|
||||||
|
|
||||||
|
| Service | Status | Free Tier |
|
||||||
|
|---------|--------|-----------|
|
||||||
|
| Groq (Llama 3) | ${{ needs.groq-analysis.result }} | 14,400 req/day |
|
||||||
|
| Mistral | skipped | 1M tokens/month |
|
||||||
|
| Cohere | skipped | 1000 req/month |
|
||||||
|
| Cloudflare AI | skipped | 10K neurons/day |
|
||||||
|
|
||||||
|
---
|
||||||
|
_Add API keys to your fork secrets to enable more services._
|
||||||
|
_All analysis runs on contributor's free tier allowance._
|
||||||
|
`;
|
||||||
|
|
||||||
|
// Only comment if at least one analysis ran
|
||||||
|
if ('${{ needs.groq-analysis.result }}' !== 'skipped') {
|
||||||
|
await github.rest.issues.createComment({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: context.issue.number,
|
||||||
|
body: summary
|
||||||
|
});
|
||||||
|
}
|
||||||
163
.github/workflows/free-tier-scanners.yml
vendored
Normal file
163
.github/workflows/free-tier-scanners.yml
vendored
Normal file
|
|
@ -0,0 +1,163 @@
|
||||||
|
name: Free Tier Security Scanners
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [dev, main]
|
||||||
|
pull_request:
|
||||||
|
branches: [dev, main]
|
||||||
|
schedule:
|
||||||
|
- cron: '0 6 * * 1' # Weekly Monday 6am
|
||||||
|
|
||||||
|
permissions:
|
||||||
|
contents: read
|
||||||
|
security-events: write
|
||||||
|
pull-requests: write
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
# Semgrep - FREE, powerful SAST
|
||||||
|
semgrep:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
container:
|
||||||
|
image: semgrep/semgrep
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Semgrep Scan
|
||||||
|
run: |
|
||||||
|
semgrep scan --config auto --sarif --output semgrep.sarif || true
|
||||||
|
|
||||||
|
- name: Upload SARIF
|
||||||
|
uses: github/codeql-action/upload-sarif@v3
|
||||||
|
with:
|
||||||
|
sarif_file: semgrep.sarif
|
||||||
|
if: always()
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
# Trivy - FREE container/IaC scanner
|
||||||
|
trivy:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Trivy Vulnerability Scan
|
||||||
|
uses: aquasecurity/trivy-action@master
|
||||||
|
with:
|
||||||
|
scan-type: 'fs'
|
||||||
|
scan-ref: '.'
|
||||||
|
format: 'sarif'
|
||||||
|
output: 'trivy.sarif'
|
||||||
|
severity: 'CRITICAL,HIGH'
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Upload Trivy SARIF
|
||||||
|
uses: github/codeql-action/upload-sarif@v3
|
||||||
|
with:
|
||||||
|
sarif_file: trivy.sarif
|
||||||
|
if: always()
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
# Gitleaks - FREE secret scanner
|
||||||
|
gitleaks:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Gitleaks Scan
|
||||||
|
uses: gitleaks/gitleaks-action@v2
|
||||||
|
env:
|
||||||
|
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
# OSV-Scanner - FREE vulnerability DB from Google
|
||||||
|
osv-scanner:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: OSV Scanner
|
||||||
|
uses: google/osv-scanner-action@v1
|
||||||
|
with:
|
||||||
|
scan-args: |-
|
||||||
|
--recursive
|
||||||
|
--format=sarif
|
||||||
|
--output=osv.sarif
|
||||||
|
.
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Upload OSV SARIF
|
||||||
|
uses: github/codeql-action/upload-sarif@v3
|
||||||
|
with:
|
||||||
|
sarif_file: osv.sarif
|
||||||
|
if: always()
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
# Checkov - FREE IaC scanner
|
||||||
|
checkov:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Checkov Scan
|
||||||
|
uses: bridgecrewio/checkov-action@v12
|
||||||
|
with:
|
||||||
|
directory: .
|
||||||
|
framework: all
|
||||||
|
output_format: sarif
|
||||||
|
output_file_path: checkov.sarif
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
- name: Upload Checkov SARIF
|
||||||
|
uses: github/codeql-action/upload-sarif@v3
|
||||||
|
with:
|
||||||
|
sarif_file: checkov.sarif
|
||||||
|
if: always()
|
||||||
|
continue-on-error: true
|
||||||
|
|
||||||
|
# Aggregate all findings for core CLI to consume
|
||||||
|
aggregate-findings:
|
||||||
|
needs: [semgrep, trivy, gitleaks, osv-scanner, checkov]
|
||||||
|
if: always()
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Summary
|
||||||
|
run: |
|
||||||
|
echo "## 🔍 Security Scan Summary" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Scanner | Status | Free Tier |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "|---------|--------|-----------|" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Semgrep | ${{ needs.semgrep.result }} | Unlimited |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Trivy | ${{ needs.trivy.result }} | Unlimited |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Gitleaks | ${{ needs.gitleaks.result }} | Unlimited |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| OSV-Scanner | ${{ needs.osv-scanner.result }} | Unlimited |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "| Checkov | ${{ needs.checkov.result }} | Unlimited |" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "Results uploaded to GitHub Security tab." >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "_All scanners are 100% free. No API keys needed._" >> $GITHUB_STEP_SUMMARY
|
||||||
|
|
||||||
|
- name: Create findings artifact for core CLI
|
||||||
|
run: |
|
||||||
|
# Create JSON summary for core CLI to consume
|
||||||
|
cat > findings.json << 'FINDINGS'
|
||||||
|
{
|
||||||
|
"timestamp": "${{ github.event.head_commit.timestamp }}",
|
||||||
|
"commit": "${{ github.sha }}",
|
||||||
|
"scanners": {
|
||||||
|
"semgrep": "${{ needs.semgrep.result }}",
|
||||||
|
"trivy": "${{ needs.trivy.result }}",
|
||||||
|
"gitleaks": "${{ needs.gitleaks.result }}",
|
||||||
|
"osv": "${{ needs.osv-scanner.result }}",
|
||||||
|
"checkov": "${{ needs.checkov.result }}"
|
||||||
|
},
|
||||||
|
"security_tab": "https://github.com/${{ github.repository }}/security/code-scanning"
|
||||||
|
}
|
||||||
|
FINDINGS
|
||||||
|
cat findings.json
|
||||||
|
|
||||||
|
- uses: actions/upload-artifact@v4
|
||||||
|
with:
|
||||||
|
name: security-findings
|
||||||
|
path: findings.json
|
||||||
|
retention-days: 30
|
||||||
64
.github/workflows/jules-dispatch.yml
vendored
Normal file
64
.github/workflows/jules-dispatch.yml
vendored
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
name: Jules Task Dispatch
|
||||||
|
|
||||||
|
# Dispatch tasks to Jules (Copilot coding agent)
|
||||||
|
# Jules works on the contributor's fork using their Copilot Pro allowance
|
||||||
|
|
||||||
|
on:
|
||||||
|
issue_comment:
|
||||||
|
types: [created]
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
dispatch-to-jules:
|
||||||
|
# Trigger when someone comments "@jules" or "/jules"
|
||||||
|
if: contains(github.event.comment.body, '@jules') || contains(github.event.comment.body, '/jules')
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
permissions:
|
||||||
|
issues: write
|
||||||
|
pull-requests: write
|
||||||
|
steps:
|
||||||
|
- name: Parse Jules command
|
||||||
|
id: parse
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const comment = context.payload.comment.body;
|
||||||
|
|
||||||
|
// Extract task from comment
|
||||||
|
// Format: @jules <task description>
|
||||||
|
// or: /jules fix the bug in auth.php
|
||||||
|
const match = comment.match(/(?:@jules|\/jules)\s+(.+)/i);
|
||||||
|
const task = match ? match[1].trim() : null;
|
||||||
|
|
||||||
|
return { task, commenter: context.payload.comment.user.login };
|
||||||
|
|
||||||
|
- name: Create Jules task
|
||||||
|
uses: actions/github-script@v7
|
||||||
|
with:
|
||||||
|
script: |
|
||||||
|
const result = ${{ steps.parse.outputs.result }};
|
||||||
|
|
||||||
|
if (!result.task) {
|
||||||
|
await github.rest.issues.createComment({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: context.issue.number,
|
||||||
|
body: `@${result.commenter} Please specify a task for Jules:\n\n\`@jules fix the authentication bug\`\n\`@jules add unit tests for User model\`\n\`@jules refactor this to use async/await\``
|
||||||
|
});
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add copilot label to trigger Jules
|
||||||
|
await github.rest.issues.addLabels({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: context.issue.number,
|
||||||
|
labels: ['copilot', 'agent:wip']
|
||||||
|
});
|
||||||
|
|
||||||
|
// Create a sub-issue or task for Jules
|
||||||
|
await github.rest.issues.createComment({
|
||||||
|
owner: context.repo.owner,
|
||||||
|
repo: context.repo.repo,
|
||||||
|
issue_number: context.issue.number,
|
||||||
|
body: `## 🤖 Jules Task Queued\n\n**Task:** ${result.task}\n**Requested by:** @${result.commenter}\n\nJules (Copilot coding agent) will work on this using the repository owner's Copilot allowance.\n\n---\n_Tip: Fork this repo to use your own Copilot Pro allowance for faster processing._`
|
||||||
|
});
|
||||||
140
.github/workflows/template-bootstrap.yml
vendored
Normal file
140
.github/workflows/template-bootstrap.yml
vendored
Normal file
|
|
@ -0,0 +1,140 @@
|
||||||
|
name: Bootstrap from Template
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [main, dev]
|
||||||
|
workflow_dispatch:
|
||||||
|
inputs:
|
||||||
|
repo_type:
|
||||||
|
description: 'Repository type'
|
||||||
|
required: true
|
||||||
|
default: 'module'
|
||||||
|
type: choice
|
||||||
|
options:
|
||||||
|
- foundation
|
||||||
|
- module
|
||||||
|
- product
|
||||||
|
- service
|
||||||
|
- infra
|
||||||
|
- template
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
bootstrap:
|
||||||
|
# Only run if this looks like a fresh repo (no releases, few commits)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v4
|
||||||
|
with:
|
||||||
|
fetch-depth: 0
|
||||||
|
|
||||||
|
- name: Check if bootstrap needed
|
||||||
|
id: check
|
||||||
|
run: |
|
||||||
|
COMMIT_COUNT=$(git rev-list --count HEAD)
|
||||||
|
if [ "$COMMIT_COUNT" -lt 5 ]; then
|
||||||
|
echo "needs_bootstrap=true" >> $GITHUB_OUTPUT
|
||||||
|
echo "Fresh repo detected ($COMMIT_COUNT commits)"
|
||||||
|
else
|
||||||
|
echo "needs_bootstrap=false" >> $GITHUB_OUTPUT
|
||||||
|
echo "Existing repo ($COMMIT_COUNT commits) - skipping bootstrap"
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Create standard labels
|
||||||
|
if: steps.check.outputs.needs_bootstrap == 'true'
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
# Agent workflow labels
|
||||||
|
gh label create "agent:ready" --description "Task ready for AI agent" --color "0E8A16" --force || true
|
||||||
|
gh label create "agent:wip" --description "Work in progress by agent" --color "F9D0C4" --force || true
|
||||||
|
gh label create "agent:review" --description "Needs verification" --color "FBCA04" --force || true
|
||||||
|
gh label create "agent:blocked" --description "Needs human input" --color "D93F0B" --force || true
|
||||||
|
gh label create "verified" --description "Work verified" --color "0E8A16" --force || true
|
||||||
|
gh label create "verify-failed" --description "Verification failed" --color "D93F0B" --force || true
|
||||||
|
gh label create "agentic" --description "AI-consumable task" --color "5319E7" --force || true
|
||||||
|
|
||||||
|
# Type labels
|
||||||
|
gh label create "type:feature" --description "New feature" --color "0052CC" --force || true
|
||||||
|
gh label create "type:bug" --description "Bug fix" --color "D93F0B" --force || true
|
||||||
|
gh label create "type:security" --description "Security issue" --color "D93F0B" --force || true
|
||||||
|
gh label create "type:docs" --description "Documentation" --color "0075CA" --force || true
|
||||||
|
|
||||||
|
# Priority labels
|
||||||
|
gh label create "priority:critical" --description "Critical priority" --color "B60205" --force || true
|
||||||
|
gh label create "priority:high" --description "High priority" --color "D93F0B" --force || true
|
||||||
|
gh label create "priority:medium" --description "Medium priority" --color "FBCA04" --force || true
|
||||||
|
gh label create "priority:low" --description "Low priority" --color "0E8A16" --force || true
|
||||||
|
|
||||||
|
echo "✅ Labels created"
|
||||||
|
|
||||||
|
- name: Set dev as default branch
|
||||||
|
if: steps.check.outputs.needs_bootstrap == 'true'
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
# Create dev branch if it doesn't exist
|
||||||
|
git checkout -b dev 2>/dev/null || git checkout dev
|
||||||
|
git push origin dev --force-with-lease || true
|
||||||
|
|
||||||
|
# Set as default (requires admin token, may fail with GITHUB_TOKEN)
|
||||||
|
gh repo edit --default-branch dev || echo "⚠️ Could not set default branch (needs admin)"
|
||||||
|
|
||||||
|
- name: Enable security features
|
||||||
|
if: steps.check.outputs.needs_bootstrap == 'true'
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
# Enable vulnerability alerts
|
||||||
|
gh api -X PUT repos/${{ github.repository }}/vulnerability-alerts || true
|
||||||
|
|
||||||
|
# Enable automated security fixes
|
||||||
|
gh api -X PUT repos/${{ github.repository }}/automated-security-fixes || true
|
||||||
|
|
||||||
|
echo "✅ Security features enabled"
|
||||||
|
|
||||||
|
- name: Create setup instructions issue
|
||||||
|
if: steps.check.outputs.needs_bootstrap == 'true'
|
||||||
|
env:
|
||||||
|
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
run: |
|
||||||
|
gh issue create \
|
||||||
|
--title "🚀 Repository Setup Checklist" \
|
||||||
|
--label "agentic,type:docs" \
|
||||||
|
--body "## Post-Template Setup
|
||||||
|
|
||||||
|
This repo was created from the [core-devops template](https://github.com/host-uk/core-devops).
|
||||||
|
|
||||||
|
### Automated ✅
|
||||||
|
- [x] Standard labels created
|
||||||
|
- [x] Security features enabled
|
||||||
|
- [x] CodeRabbit config present
|
||||||
|
|
||||||
|
### Manual Steps
|
||||||
|
- [ ] Update \`repos.yaml\` with your package details
|
||||||
|
- [ ] Update \`CLAUDE.md\` with project-specific guidance
|
||||||
|
- [ ] Update \`README.md\` with project description
|
||||||
|
- [ ] Add to org project if needed
|
||||||
|
- [ ] Set up any required secrets (\`PROJECT_TOKEN\` for auto-project)
|
||||||
|
- [ ] Remove/customize template files
|
||||||
|
|
||||||
|
### Optional
|
||||||
|
- [ ] Enable GitHub Pages for docs
|
||||||
|
- [ ] Add to CodeRabbit (if not auto-enabled)
|
||||||
|
- [ ] Configure branch protection rules
|
||||||
|
|
||||||
|
---
|
||||||
|
_This issue was auto-created by the template bootstrap workflow._"
|
||||||
|
|
||||||
|
echo "✅ Setup issue created"
|
||||||
|
|
||||||
|
- name: Summary
|
||||||
|
if: steps.check.outputs.needs_bootstrap == 'true'
|
||||||
|
run: |
|
||||||
|
echo "## 🎉 Bootstrap Complete" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "Your repo has been configured with:" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "- ✅ Standard labels for agent workflow" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "- ✅ Security features enabled" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "- ✅ Setup checklist issue created" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "" >> $GITHUB_STEP_SUMMARY
|
||||||
|
echo "See the created issue for remaining manual steps." >> $GITHUB_STEP_SUMMARY
|
||||||
153
.github/workflows/test-setup.yml
vendored
Normal file
153
.github/workflows/test-setup.yml
vendored
Normal file
|
|
@ -0,0 +1,153 @@
|
||||||
|
name: Test Setup Scripts
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches: [dev, main]
|
||||||
|
paths:
|
||||||
|
- 'scripts/**'
|
||||||
|
- '.github/workflows/test-setup.yml'
|
||||||
|
pull_request:
|
||||||
|
branches: [dev, main]
|
||||||
|
paths:
|
||||||
|
- 'scripts/**'
|
||||||
|
- '.github/workflows/test-setup.yml'
|
||||||
|
# Weekly test to catch upstream changes (package repos, etc.)
|
||||||
|
schedule:
|
||||||
|
- cron: '0 6 * * 1' # Every Monday at 6am UTC
|
||||||
|
workflow_dispatch: # Manual trigger
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
test-linux:
|
||||||
|
name: Linux (Ubuntu)
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Run install-deps.sh
|
||||||
|
run: |
|
||||||
|
chmod +x scripts/install-deps.sh
|
||||||
|
./scripts/install-deps.sh
|
||||||
|
|
||||||
|
- name: Verify dependencies installed
|
||||||
|
run: |
|
||||||
|
echo "=== Checking installed tools ==="
|
||||||
|
git --version
|
||||||
|
gh --version
|
||||||
|
go version
|
||||||
|
php --version
|
||||||
|
composer --version
|
||||||
|
node --version
|
||||||
|
pnpm --version
|
||||||
|
echo "=== All dependencies verified ==="
|
||||||
|
|
||||||
|
- name: Run install-core.sh
|
||||||
|
run: |
|
||||||
|
chmod +x scripts/install-core.sh
|
||||||
|
./scripts/install-core.sh
|
||||||
|
env:
|
||||||
|
INSTALL_DIR: ${{ github.workspace }}/bin
|
||||||
|
|
||||||
|
- name: Verify core CLI installed
|
||||||
|
run: |
|
||||||
|
export PATH="${{ github.workspace }}/bin:$PATH"
|
||||||
|
core --version || echo "Core CLI version check"
|
||||||
|
core doctor || echo "Core doctor completed"
|
||||||
|
|
||||||
|
test-macos:
|
||||||
|
name: macOS
|
||||||
|
runs-on: macos-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Run install-deps.sh
|
||||||
|
run: |
|
||||||
|
chmod +x scripts/install-deps.sh
|
||||||
|
./scripts/install-deps.sh
|
||||||
|
|
||||||
|
- name: Verify dependencies installed
|
||||||
|
run: |
|
||||||
|
echo "=== Checking installed tools ==="
|
||||||
|
git --version
|
||||||
|
gh --version
|
||||||
|
go version
|
||||||
|
php --version
|
||||||
|
composer --version
|
||||||
|
node --version
|
||||||
|
pnpm --version
|
||||||
|
echo "=== All dependencies verified ==="
|
||||||
|
|
||||||
|
- name: Run install-core.sh
|
||||||
|
run: |
|
||||||
|
chmod +x scripts/install-core.sh
|
||||||
|
./scripts/install-core.sh
|
||||||
|
env:
|
||||||
|
INSTALL_DIR: ${{ github.workspace }}/bin
|
||||||
|
|
||||||
|
- name: Verify core CLI installed
|
||||||
|
run: |
|
||||||
|
export PATH="${{ github.workspace }}/bin:$PATH"
|
||||||
|
core --version || echo "Core CLI version check"
|
||||||
|
core doctor || echo "Core doctor completed"
|
||||||
|
|
||||||
|
test-windows:
|
||||||
|
name: Windows
|
||||||
|
runs-on: windows-latest
|
||||||
|
steps:
|
||||||
|
- name: Checkout
|
||||||
|
uses: actions/checkout@v4
|
||||||
|
|
||||||
|
- name: Run install-deps.ps1
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
# Run as current user (GitHub runners have admin)
|
||||||
|
# Modify script to skip admin check for CI
|
||||||
|
$script = Get-Content scripts/install-deps.ps1 -Raw
|
||||||
|
$script = $script -replace 'Write-Err "Please run this script as Administrator"', 'Write-Warn "Skipping admin check in CI"'
|
||||||
|
$script | Set-Content scripts/install-deps-ci.ps1
|
||||||
|
.\scripts\install-deps-ci.ps1
|
||||||
|
|
||||||
|
- name: Verify dependencies installed
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
Write-Host "=== Checking installed tools ==="
|
||||||
|
git --version
|
||||||
|
gh --version
|
||||||
|
go version
|
||||||
|
php --version
|
||||||
|
composer --version
|
||||||
|
node --version
|
||||||
|
pnpm --version
|
||||||
|
Write-Host "=== All dependencies verified ==="
|
||||||
|
|
||||||
|
- name: Run install-core.ps1
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
.\scripts\install-core.ps1
|
||||||
|
env:
|
||||||
|
INSTALL_DIR: ${{ github.workspace }}\bin
|
||||||
|
|
||||||
|
- name: Verify core CLI installed
|
||||||
|
shell: pwsh
|
||||||
|
run: |
|
||||||
|
$env:PATH = "${{ github.workspace }}\bin;$env:PATH"
|
||||||
|
core --version
|
||||||
|
core doctor
|
||||||
|
|
||||||
|
# Summary job that requires all platforms to pass
|
||||||
|
setup-complete:
|
||||||
|
name: All Platforms
|
||||||
|
needs: [test-linux, test-macos, test-windows]
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
if: always()
|
||||||
|
steps:
|
||||||
|
- name: Check results
|
||||||
|
run: |
|
||||||
|
if [ "${{ needs.test-linux.result }}" != "success" ] || \
|
||||||
|
[ "${{ needs.test-macos.result }}" != "success" ] || \
|
||||||
|
[ "${{ needs.test-windows.result }}" != "success" ]; then
|
||||||
|
echo "One or more platform tests failed"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
echo "All platform tests passed!"
|
||||||
14
.gitignore
vendored
14
.gitignore
vendored
|
|
@ -5,8 +5,15 @@ packages/*
|
||||||
# Core CLI cache (transient data, not config)
|
# Core CLI cache (transient data, not config)
|
||||||
.core/cache/
|
.core/cache/
|
||||||
|
|
||||||
# IDE
|
# IDE - share useful configs, ignore user-specific
|
||||||
.idea/
|
.idea/workspace.xml
|
||||||
|
.idea/tasks.xml
|
||||||
|
.idea/shelf/
|
||||||
|
.idea/httpRequests/
|
||||||
|
.idea/dataSources/
|
||||||
|
.idea/dataSources.local.xml
|
||||||
|
.idea/copilot*.xml
|
||||||
|
.idea/material_theme*.xml
|
||||||
.vscode/
|
.vscode/
|
||||||
*.swp
|
*.swp
|
||||||
*.swo
|
*.swo
|
||||||
|
|
@ -21,3 +28,6 @@ Thumbs.db
|
||||||
|
|
||||||
# Logs
|
# Logs
|
||||||
*.log
|
*.log
|
||||||
|
|
||||||
|
# Template - remove these lines after setup
|
||||||
|
# !TEMPLATE_SETUP.md
|
||||||
|
|
|
||||||
17
.idea/.gitignore
generated
vendored
Normal file
17
.idea/.gitignore
generated
vendored
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
# User-specific files
|
||||||
|
/workspace.xml
|
||||||
|
/tasks.xml
|
||||||
|
/shelf/
|
||||||
|
/httpRequests/
|
||||||
|
/dataSources/
|
||||||
|
/dataSources.local.xml
|
||||||
|
/copilot*.xml
|
||||||
|
|
||||||
|
# Sensitive data
|
||||||
|
/webServers.xml
|
||||||
|
/deployment.xml
|
||||||
|
/.env
|
||||||
|
|
||||||
|
# OS/editor artifacts
|
||||||
|
*.iws
|
||||||
|
.DS_Store
|
||||||
79
.idea/codeStyles/Project.xml
generated
Normal file
79
.idea/codeStyles/Project.xml
generated
Normal file
|
|
@ -0,0 +1,79 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<code_scheme name="Project" version="173">
|
||||||
|
<!-- PHP PSR-12 Style -->
|
||||||
|
<PHPCodeStyleSettings>
|
||||||
|
<option name="ALIGN_KEY_VALUE_PAIRS" value="false" />
|
||||||
|
<option name="ALIGN_PHPDOC_PARAM_NAMES" value="false" />
|
||||||
|
<option name="ALIGN_PHPDOC_COMMENTS" value="false" />
|
||||||
|
<option name="ALIGN_ASSIGNMENTS" value="false" />
|
||||||
|
<option name="ALIGN_MATCH_ARM_ARROW" value="false" />
|
||||||
|
<option name="BLANK_LINES_BEFORE_RETURN_STATEMENT" value="1" />
|
||||||
|
<option name="KEEP_RPAREN_AND_LBRACE_ON_ONE_LINE" value="true" />
|
||||||
|
<option name="SPACE_AFTER_UNARY_NOT" value="false" />
|
||||||
|
<option name="LOWER_CASE_BOOLEAN_CONST" value="true" />
|
||||||
|
<option name="LOWER_CASE_NULL_CONST" value="true" />
|
||||||
|
<option name="FORCE_SHORT_DECLARATION_ARRAY_STYLE" value="true" />
|
||||||
|
<option name="PHPDOC_BLANK_LINE_BEFORE_TAGS" value="true" />
|
||||||
|
<option name="PHPDOC_BLANK_LINES_AROUND_PARAMETERS" value="false" />
|
||||||
|
<option name="PHPDOC_WRAP_LONG_LINES" value="true" />
|
||||||
|
<option name="MULTILINE_CHAINED_CALLS_SEMICOLON_ON_NEW_LINE" value="true" />
|
||||||
|
<option name="COMMA_AFTER_LAST_ARRAY_ELEMENT" value="true" />
|
||||||
|
<option name="COMMA_AFTER_LAST_PARAMETER" value="true" />
|
||||||
|
<option name="COMMA_AFTER_LAST_MATCH_ARM" value="true" />
|
||||||
|
<option name="BLANK_LINE_BEFORE_RETURN_STATEMENT" value="true" />
|
||||||
|
<option name="NAMESPACE_BRACE_STYLE" value="1" />
|
||||||
|
</PHPCodeStyleSettings>
|
||||||
|
<codeStyleSettings language="PHP">
|
||||||
|
<option name="BLANK_LINES_AFTER_PACKAGE" value="1" />
|
||||||
|
<option name="BLANK_LINES_BEFORE_IMPORTS" value="1" />
|
||||||
|
<option name="BLANK_LINES_AFTER_IMPORTS" value="1" />
|
||||||
|
<option name="BLANK_LINES_AROUND_CLASS" value="1" />
|
||||||
|
<option name="BLANK_LINES_AROUND_METHOD" value="1" />
|
||||||
|
<option name="KEEP_FIRST_COLUMN_COMMENT" value="false" />
|
||||||
|
<option name="CLASS_BRACE_STYLE" value="1" />
|
||||||
|
<option name="METHOD_BRACE_STYLE" value="1" />
|
||||||
|
<option name="ELSE_ON_NEW_LINE" value="true" />
|
||||||
|
<option name="CATCH_ON_NEW_LINE" value="true" />
|
||||||
|
<option name="FINALLY_ON_NEW_LINE" value="true" />
|
||||||
|
<option name="ALIGN_MULTILINE_PARAMETERS" value="false" />
|
||||||
|
<option name="ALIGN_MULTILINE_FOR" value="false" />
|
||||||
|
<option name="SPACE_WITHIN_ARRAY_INITIALIZER_BRACES" value="false" />
|
||||||
|
<option name="SPACE_BEFORE_IF_PARENTHESES" value="true" />
|
||||||
|
<option name="SPACE_BEFORE_WHILE_PARENTHESES" value="true" />
|
||||||
|
<option name="SPACE_BEFORE_FOR_PARENTHESES" value="true" />
|
||||||
|
<option name="SPACE_BEFORE_CATCH_PARENTHESES" value="true" />
|
||||||
|
<option name="SPACE_BEFORE_SWITCH_PARENTHESES" value="true" />
|
||||||
|
<option name="CALL_PARAMETERS_WRAP" value="5" />
|
||||||
|
<option name="METHOD_PARAMETERS_WRAP" value="5" />
|
||||||
|
<option name="ARRAY_INITIALIZER_WRAP" value="5" />
|
||||||
|
<option name="IF_BRACE_FORCE" value="3" />
|
||||||
|
<option name="DOWHILE_BRACE_FORCE" value="3" />
|
||||||
|
<option name="WHILE_BRACE_FORCE" value="3" />
|
||||||
|
<option name="FOR_BRACE_FORCE" value="3" />
|
||||||
|
</codeStyleSettings>
|
||||||
|
<!-- JavaScript/TypeScript -->
|
||||||
|
<codeStyleSettings language="JavaScript">
|
||||||
|
<option name="SPACE_BEFORE_METHOD_PARENTHESES" value="true" />
|
||||||
|
<indentOptions>
|
||||||
|
<option name="INDENT_SIZE" value="2" />
|
||||||
|
<option name="TAB_SIZE" value="2" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<codeStyleSettings language="TypeScript">
|
||||||
|
<option name="SPACE_BEFORE_METHOD_PARENTHESES" value="true" />
|
||||||
|
<indentOptions>
|
||||||
|
<option name="INDENT_SIZE" value="2" />
|
||||||
|
<option name="TAB_SIZE" value="2" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
<!-- YAML -->
|
||||||
|
<codeStyleSettings language="yaml">
|
||||||
|
<indentOptions>
|
||||||
|
<option name="INDENT_SIZE" value="2" />
|
||||||
|
</indentOptions>
|
||||||
|
</codeStyleSettings>
|
||||||
|
</code_scheme>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
8
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
8
.idea/codeStyles/codeStyleConfig.xml
generated
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectCodeStyleConfiguration">
|
||||||
|
<state>
|
||||||
|
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
|
||||||
|
</state>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
29
.idea/core-devops.iml
generated
Normal file
29
.idea/core-devops.iml
generated
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<module type="WEB_MODULE" version="4">
|
||||||
|
<component name="NewModuleRootManager">
|
||||||
|
<content url="file://$MODULE_DIR$">
|
||||||
|
<sourceFolder url="file://$MODULE_DIR$/packages" isTestSource="false" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/packages/core-php/vendor" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/packages/core-tenant/vendor" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/packages/core-admin/vendor" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/packages/core-api/vendor" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/packages/core-mcp/vendor" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/packages/core-agentic/vendor" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/packages/core-bio/vendor" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/packages/core-social/vendor" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/packages/core-analytics/vendor" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/packages/core-notify/vendor" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/packages/core-trust/vendor" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/packages/core-support/vendor" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/packages/core-commerce/vendor" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/packages/core-content/vendor" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/packages/core-tools/vendor" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/packages/core-uptelligence/vendor" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/packages/core-developer/vendor" />
|
||||||
|
<excludeFolder url="file://$MODULE_DIR$/packages/core-template/vendor" />
|
||||||
|
<excludePattern pattern="node_modules" />
|
||||||
|
</content>
|
||||||
|
<orderEntry type="inheritedJdk" />
|
||||||
|
<orderEntry type="sourceFolder" forTests="false" />
|
||||||
|
</component>
|
||||||
|
</module>
|
||||||
33
.idea/dictionaries/hostuk.xml
generated
Normal file
33
.idea/dictionaries/hostuk.xml
generated
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
<component name="ProjectDictionaryState">
|
||||||
|
<dictionary name="hostuk">
|
||||||
|
<words>
|
||||||
|
<w>agentic</w>
|
||||||
|
<w>biohost</w>
|
||||||
|
<w>devops</w>
|
||||||
|
<w>fileable</w>
|
||||||
|
<w>hostuk</w>
|
||||||
|
<w>laravel</w>
|
||||||
|
<w>livewire</w>
|
||||||
|
<w>mcp</w>
|
||||||
|
<w>middlewares</w>
|
||||||
|
<w>multitenancy</w>
|
||||||
|
<w>namespacing</w>
|
||||||
|
<w>notifyhost</w>
|
||||||
|
<w>oauth</w>
|
||||||
|
<w>phpstan</w>
|
||||||
|
<w>pint</w>
|
||||||
|
<w>sanctum</w>
|
||||||
|
<w>serializable</w>
|
||||||
|
<w>socialhost</w>
|
||||||
|
<w>tailwindcss</w>
|
||||||
|
<w>tenancy</w>
|
||||||
|
<w>trusthost</w>
|
||||||
|
<w>uptelligence</w>
|
||||||
|
<w>uuid</w>
|
||||||
|
<w>uuids</w>
|
||||||
|
<w>vite</w>
|
||||||
|
<w>webhook</w>
|
||||||
|
<w>webhooks</w>
|
||||||
|
</words>
|
||||||
|
</dictionary>
|
||||||
|
</component>
|
||||||
26
.idea/inspectionProfiles/Host_UK.xml
generated
Normal file
26
.idea/inspectionProfiles/Host_UK.xml
generated
Normal file
|
|
@ -0,0 +1,26 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<profile version="1.0">
|
||||||
|
<option name="myName" value="Host UK" />
|
||||||
|
<!-- PHP Inspections -->
|
||||||
|
<inspection_tool class="PhpUnused" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpMissingReturnTypeInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpMissingParamTypeInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpUnusedLocalVariableInspection" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpUnusedPrivateMethodInspection" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpUnusedPrivateFieldInspection" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="PhpArrayShapeAttributeCanBeAddedInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||||
|
<inspection_tool class="PhpDocMissingThrowsInspection" enabled="false" level="WEAK WARNING" enabled_by_default="false" />
|
||||||
|
<!-- Laravel-specific: don't warn about facades -->
|
||||||
|
<inspection_tool class="PhpUndefinedMethodInspection" enabled="true" level="ERROR" enabled_by_default="true">
|
||||||
|
<scope name="Vendor" level="INFORMATION" enabled="false" />
|
||||||
|
</inspection_tool>
|
||||||
|
<!-- Ignore TODO comments in vendor -->
|
||||||
|
<inspection_tool class="TodoComment" enabled="true" level="WARNING" enabled_by_default="true">
|
||||||
|
<scope name="Vendor" level="INFORMATION" enabled="false" />
|
||||||
|
</inspection_tool>
|
||||||
|
<!-- TypeScript/JavaScript -->
|
||||||
|
<inspection_tool class="TypeScriptUnresolvedReference" enabled="true" level="ERROR" enabled_by_default="true" />
|
||||||
|
<inspection_tool class="JSUnusedLocalSymbols" enabled="true" level="WARNING" enabled_by_default="true" />
|
||||||
|
</profile>
|
||||||
|
</component>
|
||||||
8
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
8
.idea/inspectionProfiles/profiles_settings.xml
generated
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<component name="InspectionProjectProfileManager">
|
||||||
|
<settings>
|
||||||
|
<option name="USE_PROJECT_PROFILE" value="true" />
|
||||||
|
<option name="PROJECT_PROFILE" value="Host UK" />
|
||||||
|
<version value="1.0" />
|
||||||
|
</settings>
|
||||||
|
</component>
|
||||||
16
.idea/laravel-idea.xml
generated
Normal file
16
.idea/laravel-idea.xml
generated
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="LaravelSettings">
|
||||||
|
<option name="routeNamespaceModule" value="" />
|
||||||
|
<option name="routeNamespaceWeb" value="" />
|
||||||
|
<option name="viewPath" value="" />
|
||||||
|
<option name="routeNamespaceApi" value="" />
|
||||||
|
<option name="controllerNamespace" value="" />
|
||||||
|
<option name="basePath" value="$PROJECT_DIR$/packages/core-php" />
|
||||||
|
<option name="apiResourceNamespace" value="" />
|
||||||
|
<option name="resourceNamespace" value="" />
|
||||||
|
<option name="multipleModules" value="true" />
|
||||||
|
<option name="livewireEnabled" value="true" />
|
||||||
|
<option name="bladeDirectiveIgnorePrefix" value="" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
9
.idea/misc.xml
generated
Normal file
9
.idea/misc.xml
generated
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="17" project-jdk-type="JavaSDK">
|
||||||
|
<output url="file://$PROJECT_DIR$/out" />
|
||||||
|
</component>
|
||||||
|
<component name="JavaScriptSettings">
|
||||||
|
<option name="languageLevel" value="ES6" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectModuleManager">
|
||||||
|
<modules>
|
||||||
|
<module fileurl="file://$PROJECT_DIR$/.idea/core-devops.iml" filepath="$PROJECT_DIR$/.idea/core-devops.iml" />
|
||||||
|
</modules>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
17
.idea/php.xml
generated
Normal file
17
.idea/php.xml
generated
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="PhpProjectSharedConfiguration" php_language_level="8.4">
|
||||||
|
<option name="suggestChangeDefaultLanguageLevel" value="false" />
|
||||||
|
</component>
|
||||||
|
<component name="PhpIncludePathManager">
|
||||||
|
<include_path>
|
||||||
|
<path value="$PROJECT_DIR$/packages/core-php/vendor" />
|
||||||
|
</include_path>
|
||||||
|
</component>
|
||||||
|
<component name="PhpStanOptionsConfiguration">
|
||||||
|
<option name="transferred" value="true" />
|
||||||
|
</component>
|
||||||
|
<component name="PhpCSFixerOptionsConfiguration">
|
||||||
|
<option name="transferred" value="true" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
15
.idea/runConfigurations/Clone_All_Repos.xml
generated
Normal file
15
.idea/runConfigurations/Clone_All_Repos.xml
generated
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Clone All Repos" type="ShConfigurationType">
|
||||||
|
<option name="SCRIPT_TEXT" value="" />
|
||||||
|
<option name="INDEPENDENT_SCRIPT_PATH" value="true" />
|
||||||
|
<option name="SCRIPT_PATH" value="$PROJECT_DIR$/scripts/clone-repos.ps1" />
|
||||||
|
<option name="SCRIPT_OPTIONS" value="" />
|
||||||
|
<option name="INDEPENDENT_SCRIPT_WORKING_DIRECTORY" value="true" />
|
||||||
|
<option name="SCRIPT_WORKING_DIRECTORY" value="$PROJECT_DIR$" />
|
||||||
|
<option name="INDEPENDENT_INTERPRETER_PATH" value="true" />
|
||||||
|
<option name="INTERPRETER_PATH" value="powershell" />
|
||||||
|
<option name="INTERPRETER_OPTIONS" value="-ExecutionPolicy Bypass -File" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
8
.idea/runConfigurations/Composer_Lint__core_php_.xml
generated
Normal file
8
.idea/runConfigurations/Composer_Lint__core_php_.xml
generated
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Composer Lint (core-php)" type="ComposerRunConfigurationType">
|
||||||
|
<option name="command" value="lint" />
|
||||||
|
<option name="workingDir" value="$PROJECT_DIR$/packages/core-php" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
8
.idea/runConfigurations/Composer_Test__core_php_.xml
generated
Normal file
8
.idea/runConfigurations/Composer_Test__core_php_.xml
generated
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="Composer Test (core-php)" type="ComposerRunConfigurationType">
|
||||||
|
<option name="command" value="test" />
|
||||||
|
<option name="workingDir" value="$PROJECT_DIR$/packages/core-php" />
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
19
.idea/runConfigurations/PHPStan__core_php_.xml
generated
Normal file
19
.idea/runConfigurations/PHPStan__core_php_.xml
generated
Normal file
|
|
@ -0,0 +1,19 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<component name="ProjectRunConfigurationManager">
|
||||||
|
<configuration default="false" name="PHPStan (core-php)" type="PhpUnitRunConfigurationType" factoryName="PHPUnit">
|
||||||
|
<CommandLine workingDirectory="$PROJECT_DIR$/packages/core-php" />
|
||||||
|
<ExternalSystemSettings>
|
||||||
|
<option name="executionName" />
|
||||||
|
<option name="externalProjectPath" />
|
||||||
|
<option name="externalSystemIdString" value="com.jetbrains.php.phpunit" />
|
||||||
|
<option name="scriptParameters" value="analyse" />
|
||||||
|
<option name="vmOptions" />
|
||||||
|
</ExternalSystemSettings>
|
||||||
|
<EXTENSION ID="PhpQualityToolRunConfigurationExtensionSettingsManager">
|
||||||
|
<QualityTool>
|
||||||
|
<option name="tool" value="PHPStan" />
|
||||||
|
</QualityTool>
|
||||||
|
</EXTENSION>
|
||||||
|
<method v="2" />
|
||||||
|
</configuration>
|
||||||
|
</component>
|
||||||
4
.idea/scopes/Packages.xml
generated
Normal file
4
.idea/scopes/Packages.xml
generated
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<component name="DependencyValidationManager">
|
||||||
|
<scope name="Packages" pattern="file[core-devops]:packages//*" />
|
||||||
|
</component>
|
||||||
4
.idea/scopes/Tests.xml
generated
Normal file
4
.idea/scopes/Tests.xml
generated
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<component name="DependencyValidationManager">
|
||||||
|
<scope name="Tests" pattern="file[core-devops]:packages//tests//*||file[core-devops]:packages//*/Tests//*" />
|
||||||
|
</component>
|
||||||
4
.idea/scopes/Vendor.xml
generated
Normal file
4
.idea/scopes/Vendor.xml
generated
Normal file
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<component name="DependencyValidationManager">
|
||||||
|
<scope name="Vendor" pattern="file[core-devops]:packages//vendor//*" />
|
||||||
|
</component>
|
||||||
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="VcsDirectoryMappings">
|
||||||
|
<mapping directory="" vcs="Git" />
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
25
.idea/watcherTasks.xml
generated
Normal file
25
.idea/watcherTasks.xml
generated
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<project version="4">
|
||||||
|
<component name="ProjectTasksOptions">
|
||||||
|
<TaskOptions isEnabled="false">
|
||||||
|
<option name="arguments" value="$FilePath$" />
|
||||||
|
<option name="checkSyntaxErrors" value="true" />
|
||||||
|
<option name="description" value="Laravel Pint - Format on save" />
|
||||||
|
<option name="exitCodeBehavior" value="ERROR" />
|
||||||
|
<option name="fileExtension" value="php" />
|
||||||
|
<option name="immediateSync" value="false" />
|
||||||
|
<option name="name" value="Pint" />
|
||||||
|
<option name="output" value="" />
|
||||||
|
<option name="outputFilters">
|
||||||
|
<array />
|
||||||
|
</option>
|
||||||
|
<option name="outputFromStdout" value="false" />
|
||||||
|
<option name="program" value="$ProjectFileDir$/packages/core-php/vendor/bin/pint" />
|
||||||
|
<option name="runOnExternalChanges" value="false" />
|
||||||
|
<option name="scopeName" value="Packages" />
|
||||||
|
<option name="trackOnlyRoot" value="true" />
|
||||||
|
<option name="workingDir" value="$FileDir$" />
|
||||||
|
<envs />
|
||||||
|
</TaskOptions>
|
||||||
|
</component>
|
||||||
|
</project>
|
||||||
78
.vitepress/config.ts
Normal file
78
.vitepress/config.ts
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
import { defineConfig } from 'vitepress'
|
||||||
|
|
||||||
|
const pkg = 'devops'
|
||||||
|
const canonical = `https://core.help/packages/${pkg}/`
|
||||||
|
|
||||||
|
export default defineConfig({
|
||||||
|
title: 'Host UK DevOps',
|
||||||
|
description: 'Developer workspace orchestrator for Host UK',
|
||||||
|
|
||||||
|
srcDir: 'doc',
|
||||||
|
outDir: '.vitepress/dist',
|
||||||
|
|
||||||
|
head: [
|
||||||
|
['link', { rel: 'canonical', href: canonical }],
|
||||||
|
['meta', { property: 'og:site_name', content: 'Host UK Documentation' }],
|
||||||
|
],
|
||||||
|
|
||||||
|
themeConfig: {
|
||||||
|
nav: [
|
||||||
|
{ text: 'Home', link: '/' },
|
||||||
|
{ text: 'core.help', link: 'https://core.help' },
|
||||||
|
],
|
||||||
|
|
||||||
|
sidebar: [
|
||||||
|
{
|
||||||
|
text: 'Guide',
|
||||||
|
items: [
|
||||||
|
{ text: 'Introduction', link: '/' },
|
||||||
|
{ text: 'Quick Start', link: '/quick-start' },
|
||||||
|
{ text: 'Commands', link: '/commands' },
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Configuration',
|
||||||
|
items: [
|
||||||
|
{ text: '.core/ Folder', link: '/core-folder' },
|
||||||
|
{ text: 'repos.yaml', link: '/repos-yaml' },
|
||||||
|
]
|
||||||
|
},
|
||||||
|
{
|
||||||
|
text: 'Reference',
|
||||||
|
items: [
|
||||||
|
{ text: 'Package Types', link: '/package-types' },
|
||||||
|
{ text: 'Troubleshooting', link: '/troubleshooting' },
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
|
||||||
|
socialLinks: [
|
||||||
|
{ icon: 'github', link: 'https://github.com/host-uk/core-devops' }
|
||||||
|
],
|
||||||
|
|
||||||
|
footer: {
|
||||||
|
message: 'Released under the EUPL-1.2 License.',
|
||||||
|
copyright: 'Copyright © Host UK'
|
||||||
|
},
|
||||||
|
|
||||||
|
search: {
|
||||||
|
provider: 'local'
|
||||||
|
},
|
||||||
|
|
||||||
|
editLink: {
|
||||||
|
pattern: 'https://github.com/host-uk/core-devops/edit/dev/doc/:path',
|
||||||
|
text: 'Edit this page on GitHub'
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
sitemap: {
|
||||||
|
hostname: canonical
|
||||||
|
},
|
||||||
|
|
||||||
|
transformHead({ pageData }) {
|
||||||
|
const head: any[] = []
|
||||||
|
const pagePath = pageData.relativePath.replace(/\.md$/, '.html').replace(/index\.html$/, '')
|
||||||
|
head.push(['link', { rel: 'canonical', href: `${canonical}${pagePath}` }])
|
||||||
|
return head
|
||||||
|
}
|
||||||
|
})
|
||||||
33
.vitepress/theme/custom.css
Normal file
33
.vitepress/theme/custom.css
Normal file
|
|
@ -0,0 +1,33 @@
|
||||||
|
.dev-banner {
|
||||||
|
background: linear-gradient(90deg, #7c3aed 0%, #2563eb 100%);
|
||||||
|
color: white;
|
||||||
|
padding: 0.5rem 1rem;
|
||||||
|
text-align: center;
|
||||||
|
font-size: 0.875rem;
|
||||||
|
position: sticky;
|
||||||
|
top: 0;
|
||||||
|
z-index: 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dev-banner a {
|
||||||
|
color: #fbbf24;
|
||||||
|
font-weight: 600;
|
||||||
|
text-decoration: underline;
|
||||||
|
}
|
||||||
|
|
||||||
|
.dev-banner a:hover {
|
||||||
|
color: #fcd34d;
|
||||||
|
}
|
||||||
|
|
||||||
|
.VPNav {
|
||||||
|
top: 36px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.VPSidebar {
|
||||||
|
top: calc(var(--vp-nav-height) + 36px) !important;
|
||||||
|
height: calc(100vh - var(--vp-nav-height) - 36px) !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.VPContent {
|
||||||
|
padding-top: 36px;
|
||||||
|
}
|
||||||
21
.vitepress/theme/index.ts
Normal file
21
.vitepress/theme/index.ts
Normal file
|
|
@ -0,0 +1,21 @@
|
||||||
|
import { h } from 'vue'
|
||||||
|
import DefaultTheme from 'vitepress/theme'
|
||||||
|
import type { Theme } from 'vitepress'
|
||||||
|
import './custom.css'
|
||||||
|
|
||||||
|
const Banner = () => {
|
||||||
|
return h('div', { class: 'dev-banner' }, [
|
||||||
|
h('span', '📚 Developer preview. '),
|
||||||
|
h('a', { href: 'https://core.help/packages/devops/', target: '_blank' }, 'Visit core.help'),
|
||||||
|
h('span', ' for the complete documentation.')
|
||||||
|
])
|
||||||
|
}
|
||||||
|
|
||||||
|
export default {
|
||||||
|
extends: DefaultTheme,
|
||||||
|
Layout() {
|
||||||
|
return h(DefaultTheme.Layout, null, {
|
||||||
|
'layout-top': () => h(Banner)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
} satisfies Theme
|
||||||
43
CLAUDE.md
43
CLAUDE.md
|
|
@ -53,12 +53,38 @@ See `.core/docs/core-folder-spec.md` for the full specification that each packag
|
||||||
```bash
|
```bash
|
||||||
# macOS/Linux
|
# macOS/Linux
|
||||||
git clone git@github.com:host-uk/core-devops.git && cd core-devops && make setup
|
git clone git@github.com:host-uk/core-devops.git && cd core-devops && make setup
|
||||||
|
|
||||||
# Windows (PowerShell as Admin)
|
|
||||||
.\scripts\install-deps.ps1 && .\scripts\install-core.ps1 && core setup
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Environment variables for `install-core.sh`:
|
### Windows Setup
|
||||||
|
|
||||||
|
The `core` CLI is not yet available on Windows. Use these steps instead:
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
# 1. Install dependencies (PowerShell as Admin)
|
||||||
|
.\scripts\install-deps.ps1
|
||||||
|
|
||||||
|
# 2. Authenticate GitHub CLI
|
||||||
|
gh auth login -h github.com -p https -s workflow,repo,read:org,read:project,project
|
||||||
|
|
||||||
|
# 3. Clone all repos
|
||||||
|
.\scripts\clone-repos.ps1
|
||||||
|
|
||||||
|
# 4. Enable PHP extensions (edit C:\tools\php84\php.ini, uncomment these):
|
||||||
|
# extension=curl
|
||||||
|
# extension=fileinfo
|
||||||
|
# extension=mbstring
|
||||||
|
# extension=openssl
|
||||||
|
# extension=pdo_sqlite
|
||||||
|
|
||||||
|
# 5. Install and test a package
|
||||||
|
cd packages/core-php
|
||||||
|
composer install
|
||||||
|
composer test
|
||||||
|
```
|
||||||
|
|
||||||
|
### Environment Variables (macOS/Linux)
|
||||||
|
|
||||||
|
For `install-core.sh`:
|
||||||
- `INSTALL_DIR` - Binary location (default: `~/.local/bin`)
|
- `INSTALL_DIR` - Binary location (default: `~/.local/bin`)
|
||||||
- `BUILD_FROM_SOURCE` - `true`, `false`, or `auto` (default: `auto`, tries binary then builds)
|
- `BUILD_FROM_SOURCE` - `true`, `false`, or `auto` (default: `auto`, tries binary then builds)
|
||||||
|
|
||||||
|
|
@ -136,9 +162,16 @@ Defined in `repos.yaml`:
|
||||||
## Troubleshooting
|
## Troubleshooting
|
||||||
|
|
||||||
- **"core: command not found"** → `make install-core` (builds from https://github.com/host-uk/core)
|
- **"core: command not found"** → `make install-core` (builds from https://github.com/host-uk/core)
|
||||||
- **"gh: command not found"** → `brew install gh && gh auth login`
|
- **"gh: command not found"** → `brew install gh && gh auth login -h github.com -p https -s workflow,repo,read:org,read:project,project`
|
||||||
|
- **"refusing to allow..." or "missing required scopes"** → `gh auth refresh -h github.com -s workflow,read:project,project`
|
||||||
- **Clone failures** → `ssh -T git@github.com` to verify SSH keys
|
- **Clone failures** → `ssh -T git@github.com` to verify SSH keys
|
||||||
|
|
||||||
|
### Windows-Specific
|
||||||
|
|
||||||
|
- **"openssl extension is required"** → Enable extensions in `C:\tools\php84\php.ini` (see setup above)
|
||||||
|
- **"composer: command not found"** → Use PowerShell, not Git Bash: `powershell -Command "composer install"`
|
||||||
|
- **core CLI not available** → Use `.\scripts\clone-repos.ps1` and work directly with composer
|
||||||
|
|
||||||
## This Repo's Scope
|
## This Repo's Scope
|
||||||
|
|
||||||
Don't add application code here. This repo only contains:
|
Don't add application code here. This repo only contains:
|
||||||
|
|
|
||||||
139
CONTRIBUTING.md
Normal file
139
CONTRIBUTING.md
Normal file
|
|
@ -0,0 +1,139 @@
|
||||||
|
# Contributing Compute to Host UK
|
||||||
|
|
||||||
|
**Host UK is a UK Community Interest Company (CIC)** - a social enterprise legally required to use our work for community benefit. Our assets are locked for public good, not shareholders.
|
||||||
|
|
||||||
|
## The Mission
|
||||||
|
|
||||||
|
1. **Build tools** that make development easier (core CLI, modules)
|
||||||
|
2. **Aggregate free compute** from community members' unused allowances
|
||||||
|
3. **Give back** by fixing security issues in unfunded OSS projects
|
||||||
|
|
||||||
|
The LLMs learned to code from open source. We're directing resources back to those projects.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Contribute Compute (5 minutes)
|
||||||
|
|
||||||
|
You don't need to write code. Your unused free tier allowances become part of a distributed network that fixes OSS.
|
||||||
|
|
||||||
|
### Step 1: Fork this repo
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gh repo fork host-uk/core-devops --clone
|
||||||
|
cd core-devops
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 2: Add your free API keys
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Gemini (1500 req/day free)
|
||||||
|
# Get key: https://aistudio.google.com/apikey
|
||||||
|
gh secret set GEMINI_API_KEY
|
||||||
|
|
||||||
|
# Groq (14,400 req/day free)
|
||||||
|
# Get key: https://console.groq.com/keys
|
||||||
|
gh secret set GROQ_API_KEY
|
||||||
|
|
||||||
|
# Optional: More services
|
||||||
|
gh secret set MISTRAL_API_KEY # https://console.mistral.ai/
|
||||||
|
gh secret set COHERE_API_KEY # https://dashboard.cohere.com/
|
||||||
|
```
|
||||||
|
|
||||||
|
### Step 3: Enable GitHub Actions
|
||||||
|
|
||||||
|
Go to your fork → Actions tab → Enable workflows
|
||||||
|
|
||||||
|
### Step 4: Done!
|
||||||
|
|
||||||
|
Your fork now:
|
||||||
|
- Runs security scans (Semgrep, Trivy, Gitleaks) - **free, no keys needed**
|
||||||
|
- Runs AI analysis when you work on PRs - **uses your free tier**
|
||||||
|
- Contributes to the distributed verification network
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Contribute Verification (10 min/week)
|
||||||
|
|
||||||
|
Help verify other agents' work (human or AI). No agent can verify their own work.
|
||||||
|
|
||||||
|
### Find tasks:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Install core CLI
|
||||||
|
make install-core
|
||||||
|
|
||||||
|
# Find tasks needing verification
|
||||||
|
core issues --label agent:review
|
||||||
|
|
||||||
|
# Or browse: https://github.com/orgs/host-uk/projects/2
|
||||||
|
```
|
||||||
|
|
||||||
|
### Verify:
|
||||||
|
|
||||||
|
1. Review the implementation
|
||||||
|
2. Check tests pass
|
||||||
|
3. Add `verified` or `verify-failed` label
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Contribute Code
|
||||||
|
|
||||||
|
Standard PR workflow:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create branch
|
||||||
|
git checkout -b fix/issue-42
|
||||||
|
|
||||||
|
# Make changes, commit
|
||||||
|
git add . && git commit -m "fix: description"
|
||||||
|
|
||||||
|
# Push (CI runs on YOUR allowance, not ours)
|
||||||
|
git push origin fix/issue-42
|
||||||
|
|
||||||
|
# Create PR
|
||||||
|
gh pr create
|
||||||
|
```
|
||||||
|
|
||||||
|
Your PR will be:
|
||||||
|
- Analyzed by AI (Gemini, Groq) - your free tier
|
||||||
|
- Scanned for security issues - free
|
||||||
|
- Reviewed by CodeRabbit - free
|
||||||
|
- Verified by a different contributor
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## The Economics
|
||||||
|
|
||||||
|
| Who | Pays For |
|
||||||
|
|-----|----------|
|
||||||
|
| Microsoft | GitHub Actions (2000 min/month per user) |
|
||||||
|
| Google | Gemini API (1500 req/day per user) |
|
||||||
|
| Groq | Llama 3 inference (14,400 req/day per user) |
|
||||||
|
| Contributors | Nothing ($0) |
|
||||||
|
| Host UK | Nothing ($0) |
|
||||||
|
| OSS Projects | Get free security fixes |
|
||||||
|
|
||||||
|
**100 contributors × free tiers = enterprise-scale compute for public good**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Where the Work Goes
|
||||||
|
|
||||||
|
1. **Host UK packages** - Our tools and modules
|
||||||
|
2. **Unfunded OSS** - Popular packages with no security budget
|
||||||
|
3. **Community requests** - Projects our members depend on
|
||||||
|
|
||||||
|
We're not hoarding. We're redistributing tech resources to the commons.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Questions?
|
||||||
|
|
||||||
|
- Discord: https://discord.gg/host-uk
|
||||||
|
- Issues: https://github.com/host-uk/core-devops/issues
|
||||||
|
|
||||||
|
**License:** EUPL-1.2 (copyleft, EU-recognized, compatible with GPL)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Host UK CIC - Building ethical infrastructure for the open source community*
|
||||||
|
|
@ -32,7 +32,7 @@ You're now ready to develop. The workspace starts with `core-php` as the active
|
||||||
core doctor
|
core doctor
|
||||||
|
|
||||||
# See workspace status
|
# See workspace status
|
||||||
core health
|
core dev health
|
||||||
|
|
||||||
# Run tests in the active package (core-php)
|
# Run tests in the active package (core-php)
|
||||||
core php test
|
core php test
|
||||||
|
|
@ -136,7 +136,12 @@ make install-core
|
||||||
|
|
||||||
**"gh: command not found"**
|
**"gh: command not found"**
|
||||||
```bash
|
```bash
|
||||||
brew install gh && gh auth login
|
brew install gh && gh auth login -h github.com -p https -s workflow,repo,read:org,read:project,project
|
||||||
|
```
|
||||||
|
|
||||||
|
**"refusing to allow an OAuth App to create or update workflow"** or **"missing required scopes"**
|
||||||
|
```bash
|
||||||
|
gh auth refresh -h github.com -s workflow,read:project,project
|
||||||
```
|
```
|
||||||
|
|
||||||
**Clone failures**
|
**Clone failures**
|
||||||
|
|
|
||||||
32
SECURITY.md
Normal file
32
SECURITY.md
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
# Security Policy
|
||||||
|
|
||||||
|
## Supported Versions
|
||||||
|
|
||||||
|
| Version | Supported |
|
||||||
|
| ------- | ------------------ |
|
||||||
|
| dev | :white_check_mark: |
|
||||||
|
|
||||||
|
## Reporting a Vulnerability
|
||||||
|
|
||||||
|
**Please do not report security vulnerabilities through public GitHub issues.**
|
||||||
|
|
||||||
|
Instead, please report them via email to: **security@host.uk.com**
|
||||||
|
|
||||||
|
Include:
|
||||||
|
- Description of the vulnerability
|
||||||
|
- Steps to reproduce
|
||||||
|
- Potential impact
|
||||||
|
- Any suggested fixes (optional)
|
||||||
|
|
||||||
|
You should receive a response within 48 hours. If the issue is confirmed, we will:
|
||||||
|
1. Work on a fix privately
|
||||||
|
2. Release a patch
|
||||||
|
3. Credit you in the release notes (unless you prefer anonymity)
|
||||||
|
|
||||||
|
## Security Best Practices
|
||||||
|
|
||||||
|
When contributing to this repository:
|
||||||
|
- Never commit secrets, API keys, or credentials
|
||||||
|
- Use environment variables for sensitive configuration
|
||||||
|
- Review dependencies for known vulnerabilities
|
||||||
|
- Follow the principle of least privilege in scripts
|
||||||
86
TEMPLATE_SETUP.md
Normal file
86
TEMPLATE_SETUP.md
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
# Template Setup Guide
|
||||||
|
|
||||||
|
You've created a new repo from the **core-devops** template. Follow these steps to customize it.
|
||||||
|
|
||||||
|
## Automated Setup
|
||||||
|
|
||||||
|
When you first push, the `template-bootstrap.yml` workflow will:
|
||||||
|
- ✅ Create standard labels (agent workflow, priorities, types)
|
||||||
|
- ✅ Enable security features (Dependabot, vulnerability alerts)
|
||||||
|
- ✅ Create a setup checklist issue
|
||||||
|
|
||||||
|
## Files to Customize
|
||||||
|
|
||||||
|
### Required Changes
|
||||||
|
|
||||||
|
| File | Action |
|
||||||
|
|------|--------|
|
||||||
|
| `repos.yaml` | Replace with your package registry or delete if single-repo |
|
||||||
|
| `CLAUDE.md` | Update with your project's architecture and commands |
|
||||||
|
| `README.md` | Replace with your project description |
|
||||||
|
| `package.json` | Update name, or delete if not using VitePress |
|
||||||
|
|
||||||
|
### Optional Changes
|
||||||
|
|
||||||
|
| File | Action |
|
||||||
|
|------|--------|
|
||||||
|
| `.coderabbit.yaml` | Customize review instructions for your codebase |
|
||||||
|
| `.core/workspace.yaml` | Update active package and settings |
|
||||||
|
| `doc/` | Replace with your documentation |
|
||||||
|
| `scripts/` | Keep if useful, or replace with your setup scripts |
|
||||||
|
| `Makefile` | Update targets for your workflow |
|
||||||
|
|
||||||
|
### Files to Delete (if not needed)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# If not using VitePress docs
|
||||||
|
rm -rf .vitepress doc package.json
|
||||||
|
|
||||||
|
# If not a multi-repo workspace
|
||||||
|
rm -rf packages repos.yaml .core/workspace.yaml
|
||||||
|
|
||||||
|
# This file (after reading!)
|
||||||
|
rm TEMPLATE_SETUP.md
|
||||||
|
```
|
||||||
|
|
||||||
|
## Secrets to Configure
|
||||||
|
|
||||||
|
If using the auto-project workflow:
|
||||||
|
```bash
|
||||||
|
# Org-level secret (already set if in host-uk org)
|
||||||
|
gh secret set PROJECT_TOKEN --org YOUR_ORG --visibility all
|
||||||
|
```
|
||||||
|
|
||||||
|
## Branch Strategy
|
||||||
|
|
||||||
|
The template uses `dev` as the default branch:
|
||||||
|
- `dev` - Development (default, PRs merge here)
|
||||||
|
- `main` - Production releases
|
||||||
|
|
||||||
|
To switch to `main`-only:
|
||||||
|
```bash
|
||||||
|
gh repo edit --default-branch main
|
||||||
|
```
|
||||||
|
|
||||||
|
## Adding to Org Projects
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Add repo's issues to a project when labeled
|
||||||
|
gh workflow run auto-project.yml
|
||||||
|
```
|
||||||
|
|
||||||
|
## Verification Workflow
|
||||||
|
|
||||||
|
The template includes the agent verification workflow:
|
||||||
|
```
|
||||||
|
agent:ready → agent:wip → agent:review → verified/verify-failed
|
||||||
|
```
|
||||||
|
|
||||||
|
This enforces the rule: **no agent can verify their own work**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Delete this file once setup is complete:
|
||||||
|
```bash
|
||||||
|
rm TEMPLATE_SETUP.md && git add -A && git commit -m "chore: complete template setup"
|
||||||
|
```
|
||||||
77
TODO.md
Normal file
77
TODO.md
Normal file
|
|
@ -0,0 +1,77 @@
|
||||||
|
# TODO - Session Summary 2026-02-01
|
||||||
|
|
||||||
|
## ✅ Completed Today
|
||||||
|
|
||||||
|
### Issue Auto-Labeling
|
||||||
|
- [x] Issue templates (bug_report.yml, feature_request.yml) for core + core-devops
|
||||||
|
- [x] Auto-label workflow detects: type, project, priority, agentic keywords
|
||||||
|
- [x] Complexity dropdown in feature request template
|
||||||
|
- [x] Heuristic complexity detection (checklist count, code blocks, sections, file refs, keywords)
|
||||||
|
- [x] Retroactively labeled unlabeled issues in core repo
|
||||||
|
- [x] Test issue #70 created and auto-labeled correctly
|
||||||
|
|
||||||
|
### GitHub Org Setup
|
||||||
|
- [x] Dev branches as default (all repos)
|
||||||
|
- [x] Labels taxonomy (agent:*, priority:*, type:*, lang:*)
|
||||||
|
- [x] Discord webhooks (7 channels × 20 repos)
|
||||||
|
- [x] Branch protection rules
|
||||||
|
- [x] Org security defaults enabled
|
||||||
|
|
||||||
|
### CodeRabbit
|
||||||
|
- [x] Central config: host-uk/coderabbit
|
||||||
|
- [x] Per-repo .coderabbit.yaml (21 repos)
|
||||||
|
- [x] review_status: false
|
||||||
|
|
||||||
|
### CodeQL/Security
|
||||||
|
- [x] Enabled on all public repos
|
||||||
|
- [x] Language-appropriate scanning
|
||||||
|
|
||||||
|
### GitHub Projects
|
||||||
|
- [x] Auto-add workflow (label → project)
|
||||||
|
- [x] PROJECT_TOKEN secret set
|
||||||
|
|
||||||
|
### Agent Verification Workflow
|
||||||
|
- [x] Labels: agent:ready → agent:wip → agent:review → verified
|
||||||
|
- [x] Self-verification blocked
|
||||||
|
- [x] core/.github/workflows/agent-verify.yml
|
||||||
|
|
||||||
|
### Template Repo (core-devops)
|
||||||
|
- [x] Bootstrap workflow for new repos
|
||||||
|
- [x] TEMPLATE_SETUP.md guide
|
||||||
|
|
||||||
|
### Free Tier Integration
|
||||||
|
- [x] Gemini, Groq, Mistral, Cohere, Cloudflare workflows
|
||||||
|
- [x] Semgrep, Trivy, Gitleaks, OSV, Checkov
|
||||||
|
- [x] Jules dispatch workflow
|
||||||
|
- [x] CONTRIBUTING.md + scripts/contribute.sh
|
||||||
|
|
||||||
|
### Docs
|
||||||
|
- [x] VitePress setup
|
||||||
|
- [x] core docs sync tested
|
||||||
|
- [x] free-tier-services.md
|
||||||
|
|
||||||
|
### Container Images (core-images)
|
||||||
|
- [x] docker-compose.yml + devcontainer.json (packages/ mount)
|
||||||
|
- [x] Dual-registry workflow: GHCR + Docker Hub (lthn/*)
|
||||||
|
- [x] DOCKERHUB_USERNAME/TOKEN secrets (org-wide)
|
||||||
|
- [ ] Fix Dockerfile Python build (#2 - tiktoken, tree-sitter)
|
||||||
|
- [ ] Merge dev → main to publish images
|
||||||
|
|
||||||
|
### Core CLI Issues
|
||||||
|
- [x] #50 - linuxkit double-dash flags fix
|
||||||
|
|
||||||
|
## 🔲 Pending (Core CLI Issues Created)
|
||||||
|
|
||||||
|
- [ ] #46 - docs sync ignores packages_dir
|
||||||
|
- [ ] #47 - core qa command area
|
||||||
|
- [ ] #48 - core security command
|
||||||
|
- [ ] #49 - core monitor (aggregate free tier findings)
|
||||||
|
|
||||||
|
## 🔲 Next Steps
|
||||||
|
|
||||||
|
- [ ] Merge dev → main on repos to deploy docs
|
||||||
|
- [ ] Recruit first 10 contributors
|
||||||
|
- [ ] Rotate PROJECT_TOKEN (was shared in chat)
|
||||||
|
- [ ] Rotate DOCKERHUB_TOKEN (was shared in chat)
|
||||||
|
- [x] Add workflow to remaining PHP repos (8 repos)
|
||||||
|
- [ ] Set up external OSS project scanning
|
||||||
134
doc/commands.md
Normal file
134
doc/commands.md
Normal file
|
|
@ -0,0 +1,134 @@
|
||||||
|
# Commands Reference
|
||||||
|
|
||||||
|
All `core` CLI commands available in the workspace.
|
||||||
|
|
||||||
|
## Workspace Commands
|
||||||
|
|
||||||
|
### `core health`
|
||||||
|
|
||||||
|
Quick status summary of all repos.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
core health
|
||||||
|
# Output: 18 repos │ 2 dirty │ synced
|
||||||
|
```
|
||||||
|
|
||||||
|
### `core work`
|
||||||
|
|
||||||
|
Full workflow: status → commit → push.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
core work # Interactive
|
||||||
|
core work --status # Status table only
|
||||||
|
```
|
||||||
|
|
||||||
|
### `core commit`
|
||||||
|
|
||||||
|
Claude-assisted commits for dirty repos.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
core commit # Interactive
|
||||||
|
core commit --all # Commit all without prompting
|
||||||
|
```
|
||||||
|
|
||||||
|
### `core push`
|
||||||
|
|
||||||
|
Push repos with unpushed commits.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
core push # Interactive
|
||||||
|
core push --force # Push without confirmation
|
||||||
|
```
|
||||||
|
|
||||||
|
### `core pull`
|
||||||
|
|
||||||
|
Pull repos that are behind.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
core pull # Interactive
|
||||||
|
core pull --all # Pull all repos
|
||||||
|
```
|
||||||
|
|
||||||
|
## GitHub Integration
|
||||||
|
|
||||||
|
### `core issues`
|
||||||
|
|
||||||
|
List open issues across repos.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
core issues # All open issues
|
||||||
|
core issues --assignee @me # Assigned to you
|
||||||
|
```
|
||||||
|
|
||||||
|
### `core reviews`
|
||||||
|
|
||||||
|
List PRs needing review.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
core reviews
|
||||||
|
```
|
||||||
|
|
||||||
|
### `core ci`
|
||||||
|
|
||||||
|
GitHub Actions workflow status.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
core ci
|
||||||
|
```
|
||||||
|
|
||||||
|
## Analysis
|
||||||
|
|
||||||
|
### `core impact`
|
||||||
|
|
||||||
|
Show what depends on a package.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
core impact core-php
|
||||||
|
```
|
||||||
|
|
||||||
|
## Package Commands
|
||||||
|
|
||||||
|
### `core php test`
|
||||||
|
|
||||||
|
Run Pest tests in the active package.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
core php test
|
||||||
|
core php test --filter=ClassName
|
||||||
|
```
|
||||||
|
|
||||||
|
### `core php lint`
|
||||||
|
|
||||||
|
Run Pint linter in the active package.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
core php lint
|
||||||
|
```
|
||||||
|
|
||||||
|
### `core php dev`
|
||||||
|
|
||||||
|
Start Vite dev server in the active package.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
core php dev
|
||||||
|
```
|
||||||
|
|
||||||
|
## Setup Commands
|
||||||
|
|
||||||
|
### `core setup`
|
||||||
|
|
||||||
|
Clone repos into the workspace.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
core setup # Default (foundation + module)
|
||||||
|
core setup --only foundation,module # Specific types
|
||||||
|
```
|
||||||
|
|
||||||
|
### `core doctor`
|
||||||
|
|
||||||
|
Check environment health.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
core doctor # Check only
|
||||||
|
core doctor --fix # Attempt to fix issues
|
||||||
|
```
|
||||||
80
doc/core-folder.md
Normal file
80
doc/core-folder.md
Normal file
|
|
@ -0,0 +1,80 @@
|
||||||
|
# .core/ Folder
|
||||||
|
|
||||||
|
The `.core/` folder provides workspace configuration and Claude Code integration.
|
||||||
|
|
||||||
|
## Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
.core/
|
||||||
|
├── workspace.yaml # Workspace configuration
|
||||||
|
├── plugin/
|
||||||
|
│ ├── plugin.json # Claude Code manifest
|
||||||
|
│ ├── skills/ # Context-aware skills
|
||||||
|
│ └── hooks/ # Command hooks
|
||||||
|
└── docs/
|
||||||
|
└── core-folder-spec.md # Full specification
|
||||||
|
```
|
||||||
|
|
||||||
|
## workspace.yaml
|
||||||
|
|
||||||
|
Defines the active package and workspace settings.
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: 1
|
||||||
|
|
||||||
|
# Active package for `core php test`, etc.
|
||||||
|
active: core-php
|
||||||
|
|
||||||
|
# Default package types for `core setup`
|
||||||
|
default_only:
|
||||||
|
- foundation
|
||||||
|
- module
|
||||||
|
|
||||||
|
# Paths
|
||||||
|
packages_dir: ./packages
|
||||||
|
|
||||||
|
# Settings
|
||||||
|
settings:
|
||||||
|
suggest_core_commands: true
|
||||||
|
show_active_in_prompt: true
|
||||||
|
```
|
||||||
|
|
||||||
|
## Changing Active Package
|
||||||
|
|
||||||
|
Edit `.core/workspace.yaml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
active: core-tenant
|
||||||
|
```
|
||||||
|
|
||||||
|
Then commands run from workspace root target that package:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
core php test # Now runs in core-tenant
|
||||||
|
```
|
||||||
|
|
||||||
|
## Claude Code Plugin
|
||||||
|
|
||||||
|
The `plugin/` folder integrates with Claude Code:
|
||||||
|
|
||||||
|
### plugin.json
|
||||||
|
|
||||||
|
Manifest defining skills and commands.
|
||||||
|
|
||||||
|
### skills/
|
||||||
|
|
||||||
|
Markdown files providing context-aware guidance:
|
||||||
|
|
||||||
|
- `workspace.md` - Multi-repo navigation
|
||||||
|
- `switch-package.md` - Package switching
|
||||||
|
- `package-status.md` - Status checking
|
||||||
|
|
||||||
|
### hooks/
|
||||||
|
|
||||||
|
Shell scripts that run before/after commands:
|
||||||
|
|
||||||
|
- `prefer-core.sh` - Suggests `core` commands
|
||||||
|
|
||||||
|
## Full Specification
|
||||||
|
|
||||||
|
See `.core/docs/core-folder-spec.md` for the complete specification that packages should follow.
|
||||||
103
doc/free-tier-compute.md
Normal file
103
doc/free-tier-compute.md
Normal file
|
|
@ -0,0 +1,103 @@
|
||||||
|
# Free Tier Compute Guide
|
||||||
|
|
||||||
|
This project uses distributed compute from contributors' free tier allowances. Here's how to maximize it.
|
||||||
|
|
||||||
|
## GitHub Actions (Microsoft)
|
||||||
|
|
||||||
|
**Free tier:** 2,000 minutes/month for public repos
|
||||||
|
|
||||||
|
When you fork this repo, CI runs on YOUR allowance, not upstream's. This includes:
|
||||||
|
- Full test suite
|
||||||
|
- Linting and formatting
|
||||||
|
- Security scanning
|
||||||
|
- AI-powered triage
|
||||||
|
|
||||||
|
## Gemini API (Google)
|
||||||
|
|
||||||
|
**Free tier:** 1,500 requests/day, 1M tokens/minute
|
||||||
|
|
||||||
|
### Setup
|
||||||
|
|
||||||
|
1. Get API key: https://aistudio.google.com/apikey
|
||||||
|
2. Add to your fork's secrets:
|
||||||
|
```bash
|
||||||
|
gh secret set GEMINI_API_KEY --repo YOUR_USER/YOUR_FORK
|
||||||
|
```
|
||||||
|
|
||||||
|
The `ai-worker.yml` workflow will use your Gemini allowance for:
|
||||||
|
- Code review
|
||||||
|
- Bug detection
|
||||||
|
- Security analysis
|
||||||
|
|
||||||
|
## Jules / Copilot (GitHub)
|
||||||
|
|
||||||
|
**Free tier:** Available with GitHub Copilot (free for OSS contributors)
|
||||||
|
|
||||||
|
### Trigger Jules
|
||||||
|
|
||||||
|
Comment on any issue:
|
||||||
|
```
|
||||||
|
@jules fix the authentication bug in login.php
|
||||||
|
@jules add unit tests for the User model
|
||||||
|
@jules refactor to use async/await
|
||||||
|
```
|
||||||
|
|
||||||
|
Jules will:
|
||||||
|
1. Analyze the issue
|
||||||
|
2. Write code to fix it
|
||||||
|
3. Create a PR on your fork
|
||||||
|
4. Uses YOUR Copilot allowance
|
||||||
|
|
||||||
|
### Get Copilot Free
|
||||||
|
|
||||||
|
- Open source contributors: https://github.com/settings/copilot
|
||||||
|
- Students: GitHub Education pack
|
||||||
|
- Verified OSS maintainers: Free Copilot Pro
|
||||||
|
|
||||||
|
## CodeRabbit
|
||||||
|
|
||||||
|
**Free tier:** Unlimited for public repos
|
||||||
|
|
||||||
|
Already configured via `.coderabbit.yaml`. Reviews run automatically on PRs.
|
||||||
|
|
||||||
|
## Compute Distribution Model
|
||||||
|
|
||||||
|
```
|
||||||
|
┌────────────────────────────────────────────┐
|
||||||
|
│ CONTRIBUTOR FORK │
|
||||||
|
│ │
|
||||||
|
│ ┌─────────────┐ ┌─────────────┐ │
|
||||||
|
│ │ GitHub │ │ Gemini │ │
|
||||||
|
│ │ Actions │ │ 2.0 Flash │ │
|
||||||
|
│ │ FREE │ │ FREE │ │
|
||||||
|
│ └─────────────┘ └─────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ ┌─────────────┐ ┌─────────────┐ │
|
||||||
|
│ │ Jules/ │ │ CodeRabbit │ │
|
||||||
|
│ │ Copilot │ │ FREE │ │
|
||||||
|
│ │ FREE* │ │ │ │
|
||||||
|
│ └─────────────┘ └─────────────┘ │
|
||||||
|
│ │
|
||||||
|
│ * With Copilot Pro (free for OSS) │
|
||||||
|
└────────────────────────────────────────────┘
|
||||||
|
│
|
||||||
|
│ PR (already analyzed)
|
||||||
|
▼
|
||||||
|
┌────────────────────────────────────────────┐
|
||||||
|
│ UPSTREAM REPO │
|
||||||
|
│ │
|
||||||
|
│ Just verify fork CI passed ✓ │
|
||||||
|
│ Cost: ~$0.001 per PR │
|
||||||
|
└────────────────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
## For Donor Fleet Members
|
||||||
|
|
||||||
|
If you want to contribute compute without coding:
|
||||||
|
|
||||||
|
1. Fork the repo
|
||||||
|
2. Set up your API keys (Gemini, etc.)
|
||||||
|
3. Keep Actions enabled
|
||||||
|
4. Pick up `agent:review` tasks to verify others' work
|
||||||
|
|
||||||
|
Your free tier becomes part of the distributed compute network!
|
||||||
159
doc/free-tier-services.md
Normal file
159
doc/free-tier-services.md
Normal file
|
|
@ -0,0 +1,159 @@
|
||||||
|
# Free Tier Services Integration
|
||||||
|
|
||||||
|
> **Host UK CIC** is a UK Community Interest Company. Our assets are legally locked for community benefit - we can't extract value for shareholders. This page documents how we aggregate free compute to benefit the open source commons.
|
||||||
|
|
||||||
|
## The Model
|
||||||
|
|
||||||
|
```
|
||||||
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ 100 CONTRIBUTORS │
|
||||||
|
│ │
|
||||||
|
│ Each contributes their FREE tier allowances: │
|
||||||
|
│ • GitHub Actions: 2000 min/month │
|
||||||
|
│ • Gemini: 1500 req/day │
|
||||||
|
│ • Groq: 14,400 req/day │
|
||||||
|
│ • Copilot: Free for OSS │
|
||||||
|
│ │
|
||||||
|
│ Total daily capacity: │
|
||||||
|
│ • 150,000 Gemini requests │
|
||||||
|
│ • 1,440,000 Groq requests │
|
||||||
|
│ • 6,666 GitHub Actions hours │
|
||||||
|
│ • Unlimited security scans │
|
||||||
|
└─────────────────────────────────────────────────────────────────┘
|
||||||
|
│
|
||||||
|
▼
|
||||||
|
┌─────────────────────────────────────────────────────────────────┐
|
||||||
|
│ core monitor │
|
||||||
|
│ │
|
||||||
|
│ Aggregates findings → Creates tasks → Routes to agents │
|
||||||
|
└─────────────────────────────────────────────────────────────────┘
|
||||||
|
│
|
||||||
|
┌───────────────┴───────────────┐
|
||||||
|
▼ ▼
|
||||||
|
┌─────────────────────────┐ ┌─────────────────────────────────┐
|
||||||
|
│ HOST UK PACKAGES │ │ UNFUNDED OSS PROJECTS │
|
||||||
|
│ │ │ │
|
||||||
|
│ Our tools, modules │ │ Popular packages with no │
|
||||||
|
│ │ │ security budget - we find │
|
||||||
|
│ │ │ and fix vulns, submit PRs │
|
||||||
|
└─────────────────────────┘ └─────────────────────────────────┘
|
||||||
|
```
|
||||||
|
|
||||||
|
**The LLMs learned from open source. We're giving back.**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## AI/LLM APIs (Contributor Keys)
|
||||||
|
|
||||||
|
| Service | Free Tier | Speed | Best For |
|
||||||
|
|---------|-----------|-------|----------|
|
||||||
|
| **Groq** | 14,400 req/day | ⚡ Fastest | Quick triage, bulk analysis |
|
||||||
|
| **Gemini 2.0** | 1500 req/day | Fast | Code review, deep analysis |
|
||||||
|
| **Mistral** | 1M tokens/month | Fast | Code generation |
|
||||||
|
| **Cohere** | 1000 req/month | Medium | Classification, embeddings |
|
||||||
|
| **Cloudflare AI** | 10K neurons/day | Edge | Low latency |
|
||||||
|
| **Together.ai** | $5 credit | Fast | Multi-model |
|
||||||
|
| **Fireworks.ai** | 600 req/min | ⚡ Fast | High throughput |
|
||||||
|
| **Cerebras** | Free tier | ⚡⚡ Fastest | Bulk inference |
|
||||||
|
|
||||||
|
### Setup (2 minutes)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# In your fork
|
||||||
|
gh secret set GEMINI_API_KEY # https://aistudio.google.com/apikey
|
||||||
|
gh secret set GROQ_API_KEY # https://console.groq.com/keys
|
||||||
|
gh secret set MISTRAL_API_KEY # https://console.mistral.ai/
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Security Scanners (No Keys Needed)
|
||||||
|
|
||||||
|
All free, unlimited, run automatically:
|
||||||
|
|
||||||
|
| Scanner | Finds | Output |
|
||||||
|
|---------|-------|--------|
|
||||||
|
| **Semgrep** | SAST vulns, code patterns | SARIF → GitHub Security |
|
||||||
|
| **Trivy** | Container vulns, IaC issues | SARIF → GitHub Security |
|
||||||
|
| **Gitleaks** | Leaked secrets, API keys | SARIF → GitHub Security |
|
||||||
|
| **OSV-Scanner** | Known CVEs (Google DB) | SARIF → GitHub Security |
|
||||||
|
| **Checkov** | IaC misconfigs | SARIF → GitHub Security |
|
||||||
|
| **CodeQL** | Deep semantic analysis | Native GitHub |
|
||||||
|
| **Dependabot** | Outdated deps | Native GitHub |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Code Analysis Apps (Free for Public Repos)
|
||||||
|
|
||||||
|
Install these on your fork for extra coverage:
|
||||||
|
|
||||||
|
| App | Install | Provides |
|
||||||
|
|-----|---------|----------|
|
||||||
|
| **Snyk** | [Install](https://github.com/apps/snyk-io) | Deps + code vulns |
|
||||||
|
| **SonarCloud** | [Install](https://github.com/apps/sonarcloud) | Code quality |
|
||||||
|
| **CodeClimate** | [Install](https://github.com/apps/codeclimate) | Maintainability |
|
||||||
|
| **DeepSource** | [Install](https://github.com/apps/deepsource-io) | Autofix suggestions |
|
||||||
|
| **Codacy** | [Install](https://github.com/apps/codacy-production) | Multi-language |
|
||||||
|
| **Socket.dev** | [Install](https://github.com/apps/socket-security) | Supply chain |
|
||||||
|
| **GitGuardian** | [Install](https://github.com/apps/gitguardian) | Secret detection |
|
||||||
|
| **Aikido** | [Install](https://github.com/apps/aikido-security) | Full security suite |
|
||||||
|
| **Trunk.io** | [Install](https://github.com/apps/trunk-io) | Meta-linter (50+ tools) |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## AI Code Assistants (Free Tiers)
|
||||||
|
|
||||||
|
| Service | Free Access | Trigger |
|
||||||
|
|---------|-------------|---------|
|
||||||
|
| **Jules/Copilot** | OSS maintainers, students | `@jules fix this bug` |
|
||||||
|
| **Codeium** | Free forever | IDE extension |
|
||||||
|
| **Cody** | Free tier | IDE extension |
|
||||||
|
| **Amazon Q** | Free tier | IDE/CLI |
|
||||||
|
| **Continue.dev** | Free, open source | IDE extension |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## CI/CD Free Tiers
|
||||||
|
|
||||||
|
| Service | Free Allowance | Notes |
|
||||||
|
|---------|----------------|-------|
|
||||||
|
| **GitHub Actions** | 2000 min/month | Per user, public repos |
|
||||||
|
| **CircleCI** | 6000 min/month | Good for heavy builds |
|
||||||
|
| **GitLab CI** | 400 min/month | Alternative to GH |
|
||||||
|
| **Semaphore** | 1300 min/month | Fast builds |
|
||||||
|
| **Buildkite** | Free for OSS | Self-hosted option |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Who Pays For All This?
|
||||||
|
|
||||||
|
| Provider | Why Free? |
|
||||||
|
|----------|-----------|
|
||||||
|
| **Microsoft** | GitHub market dominance, AI training data |
|
||||||
|
| **Google** | Gemini adoption, developer mindshare |
|
||||||
|
| **Groq** | Hardware showcase, market entry |
|
||||||
|
| **Others** | Developer ecosystem, future enterprise sales |
|
||||||
|
|
||||||
|
**They need OSS developers. We need compute. Fair trade.**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Joining the Network
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Fork and setup (5 minutes)
|
||||||
|
gh repo fork host-uk/core-devops --clone
|
||||||
|
cd core-devops
|
||||||
|
./scripts/contribute.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
Your unused free tier becomes part of a collective resource that:
|
||||||
|
1. Secures Host UK packages
|
||||||
|
2. Fixes vulnerabilities in unfunded OSS
|
||||||
|
3. Gives back to the projects that trained the AIs
|
||||||
|
|
||||||
|
**Cost: $0. Impact: Massive.**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Host UK CIC - Ethical infrastructure for the open source commons*
|
||||||
56
doc/index.md
Normal file
56
doc/index.md
Normal file
|
|
@ -0,0 +1,56 @@
|
||||||
|
---
|
||||||
|
layout: home
|
||||||
|
hero:
|
||||||
|
name: "core-devops"
|
||||||
|
text: "Developer Workspace"
|
||||||
|
tagline: Unified entry point for Host UK development
|
||||||
|
actions:
|
||||||
|
- theme: brand
|
||||||
|
text: Quick Start
|
||||||
|
link: /quick-start
|
||||||
|
- theme: alt
|
||||||
|
text: View on GitHub
|
||||||
|
link: https://github.com/host-uk/core-devops
|
||||||
|
features:
|
||||||
|
- title: One Command Setup
|
||||||
|
details: Clone and run `make setup` to get a complete development environment with all dependencies.
|
||||||
|
- title: Multi-Repo Management
|
||||||
|
details: Manage 18+ Laravel packages from a single workspace using the `core` CLI.
|
||||||
|
- title: Agentic-First
|
||||||
|
details: Designed for AI-assisted development with structured issues and Claude Code integration.
|
||||||
|
---
|
||||||
|
|
||||||
|
# Host UK DevOps
|
||||||
|
|
||||||
|
The developer workspace orchestrator for Host UK - a federated monorepo containing 18 Laravel packages.
|
||||||
|
|
||||||
|
## What's Included
|
||||||
|
|
||||||
|
| Component | Purpose |
|
||||||
|
|-----------|---------|
|
||||||
|
| `repos.yaml` | Package registry with dependencies |
|
||||||
|
| `.core/` | Workspace configuration and Claude Code plugin |
|
||||||
|
| `scripts/` | Cross-platform setup scripts |
|
||||||
|
| `Makefile` | Setup orchestration |
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone git@github.com:host-uk/core-devops.git && cd core-devops && make setup
|
||||||
|
```
|
||||||
|
|
||||||
|
## Core CLI
|
||||||
|
|
||||||
|
The workspace is managed by the `core` CLI:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
core health # Status summary
|
||||||
|
core work # Commit and push workflow
|
||||||
|
core issues # GitHub issues across repos
|
||||||
|
```
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
- [Quick Start Guide](/quick-start) - Get up and running
|
||||||
|
- [Commands Reference](/commands) - All available commands
|
||||||
|
- [.core/ Configuration](/core-folder) - Workspace configuration
|
||||||
58
doc/package-types.md
Normal file
58
doc/package-types.md
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
# Package Types
|
||||||
|
|
||||||
|
Host UK packages are organised into types based on their purpose.
|
||||||
|
|
||||||
|
## Foundation
|
||||||
|
|
||||||
|
Base framework with no dependencies.
|
||||||
|
|
||||||
|
| Package | Description |
|
||||||
|
|---------|-------------|
|
||||||
|
| `core-php` | Event-driven modules, lifecycle management |
|
||||||
|
|
||||||
|
## Modules
|
||||||
|
|
||||||
|
Infrastructure services that extend the foundation.
|
||||||
|
|
||||||
|
| Package | Description | Dependencies |
|
||||||
|
|---------|-------------|--------------|
|
||||||
|
| `core-tenant` | Multi-tenancy, workspaces, users | core-php |
|
||||||
|
| `core-admin` | Admin panel, Livewire, Flux UI | core-php |
|
||||||
|
| `core-api` | REST API, rate limiting, webhooks | core-php, core-tenant |
|
||||||
|
| `core-mcp` | Model Context Protocol server | core-php |
|
||||||
|
| `core-agentic` | AI agent orchestration | core-php, core-tenant, core-mcp |
|
||||||
|
| `core-commerce` | Billing, subscriptions, Stripe | core-php, core-tenant |
|
||||||
|
| `core-content` | CMS, pages, blog posts | core-php, core-tenant |
|
||||||
|
| `core-tools` | Developer utilities | core-php |
|
||||||
|
| `core-uptelligence` | Server monitoring | core-php, core-tenant |
|
||||||
|
| `core-developer` | Developer portal, OAuth | core-php, core-tenant, core-api |
|
||||||
|
|
||||||
|
## Products
|
||||||
|
|
||||||
|
User-facing applications.
|
||||||
|
|
||||||
|
| Package | Description | Domain |
|
||||||
|
|---------|-------------|--------|
|
||||||
|
| `core-bio` | Link-in-bio pages | bio.host.uk.com |
|
||||||
|
| `core-social` | Social media scheduling | social.host.uk.com |
|
||||||
|
| `core-analytics` | Privacy-first analytics | analytics.host.uk.com |
|
||||||
|
| `core-notify` | Push notifications | notify.host.uk.com |
|
||||||
|
| `core-trust` | Social proof widgets | trust.host.uk.com |
|
||||||
|
| `core-support` | Helpdesk, ticketing | - |
|
||||||
|
|
||||||
|
## Templates
|
||||||
|
|
||||||
|
Starter templates for new projects.
|
||||||
|
|
||||||
|
| Package | Description |
|
||||||
|
|---------|-------------|
|
||||||
|
| `core-template` | Starter template |
|
||||||
|
|
||||||
|
## Meta
|
||||||
|
|
||||||
|
Workspace and tooling repos.
|
||||||
|
|
||||||
|
| Package | Description |
|
||||||
|
|---------|-------------|
|
||||||
|
| `core-devops` | This workspace |
|
||||||
|
| `core` | Go CLI and framework |
|
||||||
63
doc/quick-start.md
Normal file
63
doc/quick-start.md
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
# Quick Start
|
||||||
|
|
||||||
|
Get a complete Host UK development environment in under 5 minutes.
|
||||||
|
|
||||||
|
## Prerequisites
|
||||||
|
|
||||||
|
- Git
|
||||||
|
- GitHub CLI (`gh`)
|
||||||
|
- SSH key configured with GitHub
|
||||||
|
|
||||||
|
## Installation
|
||||||
|
|
||||||
|
### macOS / Linux
|
||||||
|
|
||||||
|
```bash
|
||||||
|
git clone git@github.com:host-uk/core-devops.git
|
||||||
|
cd core-devops
|
||||||
|
make setup
|
||||||
|
```
|
||||||
|
|
||||||
|
### Windows (PowerShell as Admin)
|
||||||
|
|
||||||
|
```powershell
|
||||||
|
git clone git@github.com:host-uk/core-devops.git
|
||||||
|
cd core-devops
|
||||||
|
.\scripts\install-deps.ps1
|
||||||
|
.\scripts\install-core.ps1
|
||||||
|
core setup
|
||||||
|
```
|
||||||
|
|
||||||
|
## What Happens
|
||||||
|
|
||||||
|
`make setup` does three things:
|
||||||
|
|
||||||
|
1. **Installs dependencies** - PHP 8.3+, Composer, Node 20+, pnpm, GitHub CLI
|
||||||
|
2. **Installs the `core` CLI** - Multi-repo management tool
|
||||||
|
3. **Clones all packages** - Into `packages/` (foundation and modules by default)
|
||||||
|
|
||||||
|
## Verify Installation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
core doctor
|
||||||
|
```
|
||||||
|
|
||||||
|
This checks that all required tools are installed and configured.
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# See workspace status
|
||||||
|
core health
|
||||||
|
|
||||||
|
# Run tests in the active package
|
||||||
|
core php test
|
||||||
|
|
||||||
|
# Work on a specific package
|
||||||
|
cd packages/core-php
|
||||||
|
composer test
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
See the [Troubleshooting Guide](/troubleshooting) for common issues.
|
||||||
78
doc/repos-yaml.md
Normal file
78
doc/repos-yaml.md
Normal file
|
|
@ -0,0 +1,78 @@
|
||||||
|
# repos.yaml
|
||||||
|
|
||||||
|
The package registry defining all repositories in the workspace.
|
||||||
|
|
||||||
|
## Format
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
version: 1
|
||||||
|
org: host-uk
|
||||||
|
base_path: ./packages
|
||||||
|
|
||||||
|
repos:
|
||||||
|
core-php:
|
||||||
|
type: foundation
|
||||||
|
description: Core PHP framework
|
||||||
|
docs: true
|
||||||
|
ci: github-actions
|
||||||
|
|
||||||
|
core-tenant:
|
||||||
|
type: module
|
||||||
|
depends_on: [core-php]
|
||||||
|
description: Multi-tenancy, workspaces
|
||||||
|
|
||||||
|
defaults:
|
||||||
|
ci: github-actions
|
||||||
|
license: EUPL-1.2
|
||||||
|
branch: main
|
||||||
|
```
|
||||||
|
|
||||||
|
## Fields
|
||||||
|
|
||||||
|
### Repository Fields
|
||||||
|
|
||||||
|
| Field | Type | Description |
|
||||||
|
|-------|------|-------------|
|
||||||
|
| `type` | string | Package type (see below) |
|
||||||
|
| `depends_on` | array | Dependencies on other packages |
|
||||||
|
| `description` | string | Short description |
|
||||||
|
| `docs` | boolean | Has documentation |
|
||||||
|
| `ci` | string | CI system (github-actions) |
|
||||||
|
| `domain` | string | Production domain (products only) |
|
||||||
|
| `clone` | boolean | Whether to clone (default: true) |
|
||||||
|
|
||||||
|
### Package Types
|
||||||
|
|
||||||
|
| Type | Purpose | Examples |
|
||||||
|
|------|---------|----------|
|
||||||
|
| `foundation` | Base framework, no dependencies | core-php |
|
||||||
|
| `module` | Infrastructure services | core-tenant, core-admin |
|
||||||
|
| `product` | User-facing applications | core-bio, core-social |
|
||||||
|
| `template` | Starter templates | core-template |
|
||||||
|
| `meta` | Workspace repos | core-devops |
|
||||||
|
|
||||||
|
## Using with CLI
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Clone specific types
|
||||||
|
core setup --only foundation,module
|
||||||
|
|
||||||
|
# Show what depends on a package
|
||||||
|
core impact core-php
|
||||||
|
```
|
||||||
|
|
||||||
|
## Dependency Graph
|
||||||
|
|
||||||
|
The `depends_on` field creates a dependency graph:
|
||||||
|
|
||||||
|
```
|
||||||
|
core-php (foundation)
|
||||||
|
├── core-tenant
|
||||||
|
├── core-admin
|
||||||
|
├── core-api
|
||||||
|
│ └── core-developer
|
||||||
|
└── core-mcp
|
||||||
|
└── core-agentic
|
||||||
|
```
|
||||||
|
|
||||||
|
Products depend on both `core-php` and `core-tenant`.
|
||||||
93
doc/troubleshooting.md
Normal file
93
doc/troubleshooting.md
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
# Troubleshooting
|
||||||
|
|
||||||
|
Common issues and solutions.
|
||||||
|
|
||||||
|
## Installation Issues
|
||||||
|
|
||||||
|
### "core: command not found"
|
||||||
|
|
||||||
|
The Core CLI isn't installed or not in PATH.
|
||||||
|
|
||||||
|
```bash
|
||||||
|
make install-core
|
||||||
|
```
|
||||||
|
|
||||||
|
Or manually:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./scripts/install-core.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
### "gh: command not found"
|
||||||
|
|
||||||
|
Install GitHub CLI:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# macOS
|
||||||
|
brew install gh
|
||||||
|
|
||||||
|
# Then authenticate
|
||||||
|
gh auth login -h github.com -p https -s workflow,repo,read:org,read:project,project
|
||||||
|
```
|
||||||
|
|
||||||
|
### Clone failures
|
||||||
|
|
||||||
|
Check your SSH keys:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh -T git@github.com
|
||||||
|
```
|
||||||
|
|
||||||
|
If using HTTPS:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gh auth setup-git
|
||||||
|
```
|
||||||
|
|
||||||
|
## GitHub Issues
|
||||||
|
|
||||||
|
### "refusing to allow an OAuth App to create or update workflow"
|
||||||
|
|
||||||
|
Missing `workflow` scope:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gh auth refresh -h github.com -s workflow
|
||||||
|
```
|
||||||
|
|
||||||
|
### "missing required scopes [read:project]"
|
||||||
|
|
||||||
|
Missing project scope:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
gh auth refresh -h github.com -s read:project,project
|
||||||
|
```
|
||||||
|
|
||||||
|
## Workspace Issues
|
||||||
|
|
||||||
|
### Tests failing in wrong package
|
||||||
|
|
||||||
|
Check the active package in `.core/workspace.yaml`:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
active: core-php # Should match the package you're testing
|
||||||
|
```
|
||||||
|
|
||||||
|
### Packages not found
|
||||||
|
|
||||||
|
Run setup to clone packages:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
core setup
|
||||||
|
```
|
||||||
|
|
||||||
|
Or clone specific types:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
core setup --only foundation,module
|
||||||
|
```
|
||||||
|
|
||||||
|
## Getting Help
|
||||||
|
|
||||||
|
1. Run `core doctor` to check environment
|
||||||
|
2. Check GitHub issues: https://github.com/host-uk/core-devops/issues
|
||||||
|
3. Ask in Discord: https://discord.gg/host-uk
|
||||||
29
docker-compose.yml
Normal file
29
docker-compose.yml
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
# Core Developer Environment
|
||||||
|
# Mounts packages/ as /workspace in the container
|
||||||
|
|
||||||
|
services:
|
||||||
|
dev:
|
||||||
|
image: ghcr.io/host-uk/core-images:developer
|
||||||
|
container_name: core-dev
|
||||||
|
hostname: core-dev
|
||||||
|
stdin_open: true
|
||||||
|
tty: true
|
||||||
|
volumes:
|
||||||
|
# Mount packages directory as workspace
|
||||||
|
- ./packages:/workspace
|
||||||
|
# Persist home directory configs
|
||||||
|
- dev-home:/root
|
||||||
|
# SSH keys for git operations
|
||||||
|
- ~/.ssh:/root/.ssh:ro
|
||||||
|
# Git config
|
||||||
|
- ~/.gitconfig:/root/.gitconfig:ro
|
||||||
|
environment:
|
||||||
|
- TERM=xterm-256color
|
||||||
|
- EDITOR=nvim
|
||||||
|
working_dir: /workspace
|
||||||
|
# Keep container running
|
||||||
|
command: ["/bin/zsh"]
|
||||||
|
|
||||||
|
volumes:
|
||||||
|
dev-home:
|
||||||
|
name: core-dev-home
|
||||||
15
package.json
Normal file
15
package.json
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
{
|
||||||
|
"name": "@host-uk/devops-docs",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"private": true,
|
||||||
|
"type": "module",
|
||||||
|
"scripts": {
|
||||||
|
"docs:dev": "vitepress dev",
|
||||||
|
"docs:build": "vitepress build",
|
||||||
|
"docs:preview": "vitepress preview"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"vitepress": "^1.5.0",
|
||||||
|
"vue": "^3.5.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -123,6 +123,13 @@ repos:
|
||||||
description: Starter template for new projects
|
description: Starter template for new projects
|
||||||
docs: false
|
docs: false
|
||||||
|
|
||||||
|
# Claude Code plugin
|
||||||
|
core-claude:
|
||||||
|
type: meta
|
||||||
|
depends_on: []
|
||||||
|
description: Claude Code plugin for Host UK monorepo
|
||||||
|
docs: false
|
||||||
|
|
||||||
# This repo (meta)
|
# This repo (meta)
|
||||||
core-devops:
|
core-devops:
|
||||||
type: meta
|
type: meta
|
||||||
|
|
|
||||||
48
scripts/clone-repos.ps1
Normal file
48
scripts/clone-repos.ps1
Normal file
|
|
@ -0,0 +1,48 @@
|
||||||
|
# Clone all Host UK repos (Windows alternative to `core setup`)
|
||||||
|
# Run: .\scripts\clone-repos.ps1
|
||||||
|
|
||||||
|
$ErrorActionPreference = "Stop"
|
||||||
|
|
||||||
|
$repos = @(
|
||||||
|
"core-php",
|
||||||
|
"core-tenant",
|
||||||
|
"core-admin",
|
||||||
|
"core-api",
|
||||||
|
"core-mcp",
|
||||||
|
"core-agentic",
|
||||||
|
"core-bio",
|
||||||
|
"core-social",
|
||||||
|
"core-analytics",
|
||||||
|
"core-notify",
|
||||||
|
"core-trust",
|
||||||
|
"core-support",
|
||||||
|
"core-commerce",
|
||||||
|
"core-content",
|
||||||
|
"core-tools",
|
||||||
|
"core-uptelligence",
|
||||||
|
"core-developer",
|
||||||
|
"core-template"
|
||||||
|
)
|
||||||
|
|
||||||
|
$packagesDir = Join-Path $PSScriptRoot "..\packages"
|
||||||
|
|
||||||
|
Write-Host "[INFO] Cloning repos to $packagesDir" -ForegroundColor Green
|
||||||
|
|
||||||
|
foreach ($repo in $repos) {
|
||||||
|
$repoPath = Join-Path $packagesDir $repo
|
||||||
|
|
||||||
|
if (Test-Path $repoPath) {
|
||||||
|
Write-Host "[SKIP] $repo already exists" -ForegroundColor Yellow
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host "[CLONE] $repo..." -ForegroundColor Cyan
|
||||||
|
gh repo clone "host-uk/$repo" $repoPath
|
||||||
|
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
Write-Host "[WARN] Failed to clone $repo" -ForegroundColor Yellow
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Write-Host ""
|
||||||
|
Write-Host "[DONE] Repos cloned. Run 'composer install' in each package." -ForegroundColor Green
|
||||||
83
scripts/contribute.sh
Executable file
83
scripts/contribute.sh
Executable file
|
|
@ -0,0 +1,83 @@
|
||||||
|
#!/bin/bash
|
||||||
|
# Host UK CIC - Contributor Setup
|
||||||
|
# One command to join the distributed compute network
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
echo "╔══════════════════════════════════════════════════════════════╗"
|
||||||
|
echo "║ Host UK CIC - Contributor Setup ║"
|
||||||
|
echo "║ ║"
|
||||||
|
echo "║ Your free tier allowances will help fix unfunded OSS ║"
|
||||||
|
echo "║ projects. Cost to you: \$0. Impact: Massive. ║"
|
||||||
|
echo "╚══════════════════════════════════════════════════════════════╝"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Check if this is a fork
|
||||||
|
REMOTE_URL=$(git remote get-url origin 2>/dev/null || echo "")
|
||||||
|
if [[ "$REMOTE_URL" == *"host-uk/core-devops"* ]]; then
|
||||||
|
echo "⚠️ This is the upstream repo, not your fork."
|
||||||
|
echo ""
|
||||||
|
echo "Run this instead:"
|
||||||
|
echo " gh repo fork host-uk/core-devops --clone"
|
||||||
|
echo " cd core-devops"
|
||||||
|
echo " ./scripts/contribute.sh"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✓ Fork detected"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Check gh auth
|
||||||
|
if ! gh auth status &>/dev/null; then
|
||||||
|
echo "⚠️ GitHub CLI not authenticated"
|
||||||
|
echo "Run: gh auth login"
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "✓ GitHub CLI authenticated"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Setup secrets
|
||||||
|
echo "═══════════════════════════════════════════════════════════════"
|
||||||
|
echo " OPTIONAL: Add API keys for AI-powered analysis"
|
||||||
|
echo " (Skip any you don't want - security scans work without them)"
|
||||||
|
echo "═══════════════════════════════════════════════════════════════"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
read -p "Add Gemini API key? (1500 req/day free) [y/N] " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
echo "Get key at: https://aistudio.google.com/apikey"
|
||||||
|
gh secret set GEMINI_API_KEY
|
||||||
|
fi
|
||||||
|
|
||||||
|
read -p "Add Groq API key? (14,400 req/day free) [y/N] " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
echo "Get key at: https://console.groq.com/keys"
|
||||||
|
gh secret set GROQ_API_KEY
|
||||||
|
fi
|
||||||
|
|
||||||
|
read -p "Add Mistral API key? (1M tokens/month free) [y/N] " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ $REPLY =~ ^[Yy]$ ]]; then
|
||||||
|
echo "Get key at: https://console.mistral.ai/"
|
||||||
|
gh secret set MISTRAL_API_KEY
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "═══════════════════════════════════════════════════════════════"
|
||||||
|
echo " ✅ SETUP COMPLETE"
|
||||||
|
echo "═══════════════════════════════════════════════════════════════"
|
||||||
|
echo ""
|
||||||
|
echo "Your fork is now part of the distributed compute network!"
|
||||||
|
echo ""
|
||||||
|
echo "What happens now:"
|
||||||
|
echo " • Security scans run automatically (Semgrep, Trivy, Gitleaks)"
|
||||||
|
echo " • AI analysis runs on your PRs (using your free tier)"
|
||||||
|
echo " • You can verify others' work: core issues --label agent:review"
|
||||||
|
echo ""
|
||||||
|
echo "The compute you contribute helps fix security issues in"
|
||||||
|
echo "unfunded open source projects. Thank you! 🙏"
|
||||||
|
echo ""
|
||||||
|
echo "Questions? https://discord.gg/host-uk"
|
||||||
|
|
@ -27,9 +27,25 @@ if ($PSVersionTable.PSVersion.Major -lt 4) {
|
||||||
}
|
}
|
||||||
|
|
||||||
$Repo = "host-uk/core"
|
$Repo = "host-uk/core"
|
||||||
$Version = "v0.1.0" # Pinned version - update when releasing new versions
|
|
||||||
$MinDiskSpaceMB = 100 # Minimum required disk space in MB
|
$MinDiskSpaceMB = 100 # Minimum required disk space in MB
|
||||||
|
|
||||||
|
# Resolve latest release version from GitHub API
|
||||||
|
function Get-LatestVersion {
|
||||||
|
try {
|
||||||
|
if (Test-Command gh) {
|
||||||
|
$version = gh release view --repo $Repo --json tagName -q '.tagName' 2>$null
|
||||||
|
if ($version) { return $version }
|
||||||
|
}
|
||||||
|
|
||||||
|
# Fallback to GitHub API
|
||||||
|
$response = Invoke-RestMethod -Uri "https://api.github.com/repos/$Repo/releases/latest" -UseBasicParsing
|
||||||
|
if ($response.tag_name) { return $response.tag_name }
|
||||||
|
} catch {
|
||||||
|
Write-Warn "Could not determine latest version, using default branch"
|
||||||
|
}
|
||||||
|
return $null
|
||||||
|
}
|
||||||
|
|
||||||
function Write-Info { Write-Host "[INFO] $args" -ForegroundColor Green }
|
function Write-Info { Write-Host "[INFO] $args" -ForegroundColor Green }
|
||||||
function Write-Warn { Write-Host "[WARN] $args" -ForegroundColor Yellow }
|
function Write-Warn { Write-Host "[WARN] $args" -ForegroundColor Yellow }
|
||||||
function Write-Err { Write-Host "[ERROR] $args" -ForegroundColor Red; exit 1 }
|
function Write-Err { Write-Host "[ERROR] $args" -ForegroundColor Red; exit 1 }
|
||||||
|
|
@ -144,7 +160,7 @@ function New-SecureDirectory {
|
||||||
# Check parent directory for symlinks first
|
# Check parent directory for symlinks first
|
||||||
$parent = Split-Path $Path -Parent
|
$parent = Split-Path $Path -Parent
|
||||||
if ($parent -and (Test-Path $parent)) {
|
if ($parent -and (Test-Path $parent)) {
|
||||||
Test-SecureDirectory -Path $parent
|
$null = Test-SecureDirectory -Path $parent
|
||||||
}
|
}
|
||||||
|
|
||||||
# Create directory
|
# Create directory
|
||||||
|
|
@ -153,7 +169,7 @@ function New-SecureDirectory {
|
||||||
}
|
}
|
||||||
|
|
||||||
# Immediately verify it's not a symlink (minimize TOCTOU window)
|
# Immediately verify it's not a symlink (minimize TOCTOU window)
|
||||||
Test-SecureDirectory -Path $Path
|
$null = Test-SecureDirectory -Path $Path
|
||||||
|
|
||||||
return $Path
|
return $Path
|
||||||
}
|
}
|
||||||
|
|
@ -181,10 +197,12 @@ function Set-SecureDirectoryAcl {
|
||||||
|
|
||||||
# Add full control for current user only
|
# Add full control for current user only
|
||||||
$currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
|
$currentUser = [System.Security.Principal.WindowsIdentity]::GetCurrent().Name
|
||||||
|
# Pre-calculate flags to avoid -bor compatibility issues across PowerShell versions
|
||||||
|
$inheritFlags = [System.Security.AccessControl.InheritanceFlags]([int][System.Security.AccessControl.InheritanceFlags]::ContainerInherit + [int][System.Security.AccessControl.InheritanceFlags]::ObjectInherit)
|
||||||
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule(
|
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule(
|
||||||
$currentUser,
|
$currentUser,
|
||||||
[System.Security.AccessControl.FileSystemRights]::FullControl,
|
[System.Security.AccessControl.FileSystemRights]::FullControl,
|
||||||
[System.Security.AccessControl.InheritanceFlags]::ContainerInherit -bor [System.Security.AccessControl.InheritanceFlags]::ObjectInherit,
|
$inheritFlags,
|
||||||
[System.Security.AccessControl.PropagationFlags]::None,
|
[System.Security.AccessControl.PropagationFlags]::None,
|
||||||
[System.Security.AccessControl.AccessControlType]::Allow
|
[System.Security.AccessControl.AccessControlType]::Allow
|
||||||
)
|
)
|
||||||
|
|
@ -211,18 +229,18 @@ function Set-SecureDirectoryAcl {
|
||||||
# Download pre-built binary with integrity verification
|
# Download pre-built binary with integrity verification
|
||||||
function Download-Binary {
|
function Download-Binary {
|
||||||
$arch = if ([Environment]::Is64BitOperatingSystem) { "amd64" } else { "386" }
|
$arch = if ([Environment]::Is64BitOperatingSystem) { "amd64" } else { "386" }
|
||||||
$binaryUrl = "https://github.com/$Repo/releases/download/$Version/core-windows-$arch.exe"
|
$binaryUrl = "https://github.com/$Repo/releases/latest/download/core-windows-$arch.exe"
|
||||||
$checksumUrl = "https://github.com/$Repo/releases/download/$Version/checksums.txt"
|
$checksumUrl = "https://github.com/$Repo/releases/latest/download/checksums.txt"
|
||||||
|
|
||||||
Write-Info "Attempting to download pre-built binary (version $Version)..."
|
Write-Info "Attempting to download pre-built binary..."
|
||||||
Write-Info "URL: $binaryUrl"
|
Write-Info "URL: $binaryUrl"
|
||||||
|
|
||||||
# Track temp file for cleanup
|
# Track temp file for cleanup
|
||||||
$tempExe = $null
|
$tempExe = $null
|
||||||
|
|
||||||
try {
|
try {
|
||||||
# Create and verify install directory
|
# Create and verify install directory (suppress output to avoid polluting return value)
|
||||||
New-SecureDirectory -Path $InstallDir
|
$null = New-SecureDirectory -Path $InstallDir
|
||||||
|
|
||||||
# Use a temp file in the same directory (same filesystem for atomic move)
|
# Use a temp file in the same directory (same filesystem for atomic move)
|
||||||
$tempExe = Join-Path $InstallDir "core.exe.tmp.$([System.Guid]::NewGuid().ToString('N').Substring(0,8))"
|
$tempExe = Join-Path $InstallDir "core.exe.tmp.$([System.Guid]::NewGuid().ToString('N').Substring(0,8))"
|
||||||
|
|
@ -252,7 +270,7 @@ function Download-Binary {
|
||||||
Test-FileHash -FilePath $tempExe -ExpectedHash $expectedHash
|
Test-FileHash -FilePath $tempExe -ExpectedHash $expectedHash
|
||||||
|
|
||||||
# Re-verify directory hasn't been replaced with symlink (reduce TOCTOU window)
|
# Re-verify directory hasn't been replaced with symlink (reduce TOCTOU window)
|
||||||
Test-SecureDirectory -Path $InstallDir
|
$null = Test-SecureDirectory -Path $InstallDir
|
||||||
|
|
||||||
# Atomic move to final location (same filesystem)
|
# Atomic move to final location (same filesystem)
|
||||||
$finalPath = Join-Path $InstallDir "core.exe"
|
$finalPath = Join-Path $InstallDir "core.exe"
|
||||||
|
|
@ -297,13 +315,19 @@ function Test-GitTagSignature {
|
||||||
Push-Location $RepoPath
|
Push-Location $RepoPath
|
||||||
try {
|
try {
|
||||||
# Attempt to verify the tag signature
|
# Attempt to verify the tag signature
|
||||||
$result = git tag -v $Tag 2>&1
|
# Use $ErrorActionPreference temporarily to prevent stderr from throwing
|
||||||
if ($LASTEXITCODE -eq 0) {
|
$oldErrorAction = $ErrorActionPreference
|
||||||
|
$ErrorActionPreference = "Continue"
|
||||||
|
$result = git tag -v $Tag 2>&1 | Out-String
|
||||||
|
$exitCode = $LASTEXITCODE
|
||||||
|
$ErrorActionPreference = $oldErrorAction
|
||||||
|
|
||||||
|
if ($exitCode -eq 0) {
|
||||||
Write-Info "GPG signature verified for tag $Tag"
|
Write-Info "GPG signature verified for tag $Tag"
|
||||||
return $true
|
return $true
|
||||||
} else {
|
} else {
|
||||||
# Check if tag is unsigned vs signature invalid
|
# Check if tag is unsigned vs signature invalid
|
||||||
if ($result -match "error: no signature found") {
|
if ($result -match "no signature found" -or $result -match "cannot verify a non-tag") {
|
||||||
Write-Warn "Tag $Tag is not signed - continuing without signature verification"
|
Write-Warn "Tag $Tag is not signed - continuing without signature verification"
|
||||||
return $true
|
return $true
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -326,37 +350,72 @@ function Build-FromSource {
|
||||||
|
|
||||||
# Create secure temp directory with restrictive ACL
|
# Create secure temp directory with restrictive ACL
|
||||||
$tmpdir = Join-Path ([System.IO.Path]::GetTempPath()) "core-build-$([System.Guid]::NewGuid().ToString('N'))"
|
$tmpdir = Join-Path ([System.IO.Path]::GetTempPath()) "core-build-$([System.Guid]::NewGuid().ToString('N'))"
|
||||||
New-SecureDirectory -Path $tmpdir
|
$null = New-SecureDirectory -Path $tmpdir
|
||||||
|
|
||||||
# ACL is REQUIRED for temp build directories (security critical)
|
# ACL is REQUIRED for temp build directories (security critical)
|
||||||
Set-SecureDirectoryAcl -Path $tmpdir -Required
|
$null = Set-SecureDirectoryAcl -Path $tmpdir -Required
|
||||||
|
|
||||||
try {
|
try {
|
||||||
Write-Info "Cloning $Repo (version $Version)..."
|
# Resolve latest version for reproducible builds
|
||||||
$cloneDir = Join-Path $tmpdir "Core"
|
$version = Get-LatestVersion
|
||||||
|
if ($version) {
|
||||||
# Clone specific tag for reproducibility
|
Write-Info "Resolved latest version: $version"
|
||||||
git clone --depth 1 --branch $Version "https://github.com/$Repo.git" $cloneDir
|
} else {
|
||||||
if ($LASTEXITCODE -ne 0) {
|
Write-Warn "Building from default branch (version unknown)"
|
||||||
Write-Err "Failed to clone repository at version $Version"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# Verify GPG signature on tag (if available)
|
Write-Info "Cloning $Repo..."
|
||||||
Test-GitTagSignature -RepoPath $cloneDir -Tag $Version
|
$cloneDir = Join-Path $tmpdir "Core"
|
||||||
|
|
||||||
|
# Clone specific version if available, otherwise default branch
|
||||||
|
if ($version) {
|
||||||
|
git clone --depth 1 --branch $version "https://github.com/$Repo.git" $cloneDir
|
||||||
|
} else {
|
||||||
|
git clone --depth 1 "https://github.com/$Repo.git" $cloneDir
|
||||||
|
}
|
||||||
|
if ($LASTEXITCODE -ne 0) {
|
||||||
|
Write-Err "Failed to clone repository"
|
||||||
|
}
|
||||||
|
|
||||||
Write-Info "Building core CLI..."
|
Write-Info "Building core CLI..."
|
||||||
Push-Location $cloneDir
|
Push-Location $cloneDir
|
||||||
try {
|
try {
|
||||||
go build -o core.exe .
|
# Explicitly set GOOS/GOARCH to ensure Windows build
|
||||||
if ($LASTEXITCODE -ne 0) {
|
$env:GOOS = "windows"
|
||||||
Write-Err "Go build failed"
|
$env:GOARCH = "amd64"
|
||||||
|
|
||||||
|
$oldErrorAction = $ErrorActionPreference
|
||||||
|
$ErrorActionPreference = "Continue"
|
||||||
|
$buildOutput = go build -o core.exe . 2>&1 | Out-String
|
||||||
|
$buildExitCode = $LASTEXITCODE
|
||||||
|
$ErrorActionPreference = $oldErrorAction
|
||||||
|
|
||||||
|
if ($buildExitCode -ne 0) {
|
||||||
|
# Check for Windows-specific build issues
|
||||||
|
if ($buildOutput -match "Setpgid|Getpgid|syscall\.Kill|undefined.*syscall") {
|
||||||
|
Write-Warn "Build failed: core CLI uses Unix-specific syscalls not available on Windows."
|
||||||
|
Write-Warn ""
|
||||||
|
Write-Warn "Options:"
|
||||||
|
Write-Warn " 1. Wait for pre-built Windows binaries in GitHub releases"
|
||||||
|
Write-Warn " 2. Use WSL (Windows Subsystem for Linux) for development"
|
||||||
|
Write-Warn " 3. Work directly with composer in packages/ (core CLI is optional)"
|
||||||
|
Write-Warn ""
|
||||||
|
Write-Warn "For PHP development, you can use composer directly:"
|
||||||
|
Write-Warn " cd packages/core-php && composer test"
|
||||||
|
Write-Host ""
|
||||||
|
# Don't use Write-Err here - exit gracefully
|
||||||
|
exit 0
|
||||||
|
} else {
|
||||||
|
Write-Host $buildOutput
|
||||||
|
Write-Err "Go build failed"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} finally {
|
} finally {
|
||||||
Pop-Location
|
Pop-Location
|
||||||
}
|
}
|
||||||
|
|
||||||
# Create and verify install directory
|
# Create and verify install directory
|
||||||
New-SecureDirectory -Path $InstallDir
|
$null = New-SecureDirectory -Path $InstallDir
|
||||||
|
|
||||||
# Move built binary to install location
|
# Move built binary to install location
|
||||||
Move-Item (Join-Path $cloneDir "core.exe") (Join-Path $InstallDir "core.exe") -Force
|
Move-Item (Join-Path $cloneDir "core.exe") (Join-Path $InstallDir "core.exe") -Force
|
||||||
|
|
@ -424,10 +483,10 @@ function Verify {
|
||||||
|
|
||||||
# Main
|
# Main
|
||||||
function Main {
|
function Main {
|
||||||
Write-Info "Installing Core CLI (version $Version)..."
|
Write-Info "Installing Core CLI..."
|
||||||
|
|
||||||
# Check disk space before starting
|
# Check disk space before starting
|
||||||
Test-DiskSpace -Path $InstallDir
|
$null = Test-DiskSpace -Path $InstallDir
|
||||||
|
|
||||||
# Try download first, fallback to build
|
# Try download first, fallback to build
|
||||||
if (-not (Download-Binary)) {
|
if (-not (Download-Binary)) {
|
||||||
|
|
|
||||||
|
|
@ -21,10 +21,24 @@ set -e
|
||||||
# - No TLS certificate pinning (relies on system CA store)
|
# - No TLS certificate pinning (relies on system CA store)
|
||||||
|
|
||||||
REPO="host-uk/core"
|
REPO="host-uk/core"
|
||||||
VERSION="v0.1.0" # Pinned version - update when releasing new versions
|
VERSION="${CORE_VERSION:-latest}" # Use latest release, or set CORE_VERSION=dev for dev builds
|
||||||
INSTALL_DIR="${INSTALL_DIR:-$HOME/.local/bin}"
|
INSTALL_DIR="${INSTALL_DIR:-$HOME/.local/bin}"
|
||||||
BUILD_FROM_SOURCE="${BUILD_FROM_SOURCE:-auto}"
|
BUILD_FROM_SOURCE="${BUILD_FROM_SOURCE:-auto}"
|
||||||
|
|
||||||
|
# Resolve "latest" to actual release tag
|
||||||
|
resolve_version() {
|
||||||
|
if [[ "$VERSION" == "latest" ]]; then
|
||||||
|
if has gh; then
|
||||||
|
VERSION=$(gh release view --repo "$REPO" --json tagName -q '.tagName' 2>/dev/null) || VERSION="dev"
|
||||||
|
elif has curl; then
|
||||||
|
VERSION=$(curl -fsSL "https://api.github.com/repos/$REPO/releases/latest" 2>/dev/null | grep '"tag_name"' | head -1 | cut -d'"' -f4) || VERSION="dev"
|
||||||
|
else
|
||||||
|
VERSION="dev"
|
||||||
|
fi
|
||||||
|
info "Resolved latest version: $VERSION"
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
RED='\033[0;31m'
|
RED='\033[0;31m'
|
||||||
GREEN='\033[0;32m'
|
GREEN='\033[0;32m'
|
||||||
YELLOW='\033[1;33m'
|
YELLOW='\033[1;33m'
|
||||||
|
|
@ -75,7 +89,8 @@ verify_hash() {
|
||||||
|
|
||||||
actual_hash=$(compute_sha256 "$file")
|
actual_hash=$(compute_sha256 "$file")
|
||||||
|
|
||||||
if [[ "${actual_hash,,}" != "${expected_hash,,}" ]]; then
|
# Case-insensitive compare (bash 3 compatible)
|
||||||
|
if [[ "$(echo "$actual_hash" | tr '[:upper:]' '[:lower:]')" != "$(echo "$expected_hash" | tr '[:upper:]' '[:lower:]')" ]]; then
|
||||||
rm -f "$file"
|
rm -f "$file"
|
||||||
error "Hash verification failed! Expected: $expected_hash, Got: $actual_hash. The downloaded file may be corrupted or tampered with."
|
error "Hash verification failed! Expected: $expected_hash, Got: $actual_hash. The downloaded file may be corrupted or tampered with."
|
||||||
fi
|
fi
|
||||||
|
|
@ -282,6 +297,7 @@ verify() {
|
||||||
}
|
}
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
|
resolve_version
|
||||||
info "Installing Core CLI (version $VERSION)..."
|
info "Installing Core CLI (version $VERSION)..."
|
||||||
|
|
||||||
# Verify install directory is safe before starting
|
# Verify install directory is safe before starting
|
||||||
|
|
|
||||||
|
|
@ -102,6 +102,28 @@ function Main {
|
||||||
}
|
}
|
||||||
|
|
||||||
Write-Info "Dependencies installed!"
|
Write-Info "Dependencies installed!"
|
||||||
|
Write-Host ""
|
||||||
|
|
||||||
|
# Configure GitHub CLI if not already authenticated
|
||||||
|
if (Test-Command gh) {
|
||||||
|
$authStatus = gh auth status 2>&1 | Out-String
|
||||||
|
if ($authStatus -match "not logged in") {
|
||||||
|
Write-Info "Configuring GitHub CLI..."
|
||||||
|
Write-Host "You'll need to authenticate with GitHub."
|
||||||
|
gh auth login -h github.com -p https -s workflow,repo,read:org,read:project,project
|
||||||
|
} else {
|
||||||
|
# Check for missing scopes
|
||||||
|
$missingScopes = @()
|
||||||
|
if ($authStatus -notmatch "workflow") { $missingScopes += "workflow" }
|
||||||
|
if ($authStatus -notmatch "read:project") { $missingScopes += "read:project,project" }
|
||||||
|
|
||||||
|
if ($missingScopes.Count -gt 0) {
|
||||||
|
Write-Warn "GitHub CLI missing scopes: $($missingScopes -join ', ')"
|
||||||
|
Write-Host "Run: gh auth refresh -h github.com -s workflow,read:project,project"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
Write-Host ""
|
Write-Host ""
|
||||||
Write-Host "Next: Run '.\scripts\install-core.ps1' to install the core CLI"
|
Write-Host "Next: Run '.\scripts\install-core.ps1' to install the core CLI"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -44,7 +44,8 @@ verify_hash() {
|
||||||
|
|
||||||
actual_hash=$(compute_sha256 "$file")
|
actual_hash=$(compute_sha256 "$file")
|
||||||
|
|
||||||
if [[ "${actual_hash,,}" != "${expected_hash,,}" ]]; then
|
# Case-insensitive compare (bash 3 compatible)
|
||||||
|
if [[ "$(echo "$actual_hash" | tr '[:upper:]' '[:lower:]')" != "$(echo "$expected_hash" | tr '[:upper:]' '[:lower:]')" ]]; then
|
||||||
rm -f "$file"
|
rm -f "$file"
|
||||||
error "Hash verification failed! Expected: $expected_hash, Got: $actual_hash"
|
error "Hash verification failed! Expected: $expected_hash, Got: $actual_hash"
|
||||||
fi
|
fi
|
||||||
|
|
@ -286,6 +287,35 @@ main() {
|
||||||
esac
|
esac
|
||||||
|
|
||||||
info "Dependencies installed!"
|
info "Dependencies installed!"
|
||||||
|
echo ""
|
||||||
|
|
||||||
|
# Configure GitHub CLI if not already authenticated
|
||||||
|
if has gh; then
|
||||||
|
if ! gh auth status &>/dev/null; then
|
||||||
|
info "Configuring GitHub CLI..."
|
||||||
|
echo "You'll need to authenticate with GitHub."
|
||||||
|
echo "When prompted, select HTTPS and add the 'workflow' scope."
|
||||||
|
echo ""
|
||||||
|
gh auth login -h github.com -p https -s workflow,repo,read:org,read:project,project
|
||||||
|
else
|
||||||
|
# Check if required scopes are present
|
||||||
|
local auth_status=$(gh auth status 2>&1)
|
||||||
|
local missing_scopes=""
|
||||||
|
|
||||||
|
if ! echo "$auth_status" | grep -q workflow; then
|
||||||
|
missing_scopes="workflow"
|
||||||
|
fi
|
||||||
|
if ! echo "$auth_status" | grep -q "read:project"; then
|
||||||
|
missing_scopes="$missing_scopes read:project project"
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [[ -n "$missing_scopes" ]]; then
|
||||||
|
warn "GitHub CLI missing scopes:$missing_scopes"
|
||||||
|
echo "Run: gh auth refresh -h github.com -s workflow,read:project,project"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "Next: Run './scripts/install-core.sh' to install the core CLI"
|
echo "Next: Run './scripts/install-core.sh' to install the core CLI"
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue