Initial commit

This commit is contained in:
Your Name
2026-02-12 23:56:35 -06:00
commit b51c450659
7 changed files with 1293 additions and 0 deletions

View File

@@ -0,0 +1,265 @@
name: Bot - Documentation Update with Canva
on:
push:
branches: [main, master]
paths:
- 'src/**'
- 'lib/**'
- '*.md'
schedule:
- cron: '0 0 * * 1' # Weekly on Monday
permissions:
contents: write
pull-requests: write
jobs:
update-docs-with-visuals:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Setup Python
uses: actions/setup-python@v5
with:
python-version: '3.11'
- name: Install Canva integration
run: |
pip install requests
- name: Generate documentation
id: gen_docs
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const path = require('path');
// Extract functions and create docs
function extractDocs(filePath) {
const content = fs.readFileSync(filePath, 'utf8');
const docRegex = /\/\*\*([\s\S]*?)\*\/\s*(?:export\s+)?(?:async\s+)?function\s+(\w+)/g;
const docs = [];
let match;
while ((match = docRegex.exec(content)) !== null) {
docs.push({
name: match[2],
doc: match[1].trim(),
file: filePath
});
}
return docs;
}
function scanForFunctions(dir) {
const docs = [];
const entries = fs.readdirSync(dir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(dir, entry.name);
if (entry.name.startsWith('.') || entry.name === 'node_modules') {
continue;
}
if (entry.isDirectory()) {
docs.push(...scanForFunctions(fullPath));
} else if (entry.name.endsWith('.js') || entry.name.endsWith('.ts')) {
docs.push(...extractDocs(fullPath));
}
}
return docs;
}
if (fs.existsSync('src')) {
const docs = scanForFunctions('src');
if (docs.length > 0) {
let apiDoc = '# API Documentation\n\n';
apiDoc += '> Auto-generated from source code\n\n';
// Create diagram request for Canva
const diagramRequest = {
repository: context.repo.repo,
functions: docs.map(d => d.name),
functionCount: docs.length
};
fs.writeFileSync('canva-diagram-request.json', JSON.stringify(diagramRequest, null, 2));
for (const doc of docs) {
apiDoc += `## ${doc.name}\n\n`;
apiDoc += `**Source:** \`${doc.file}\`\n\n`;
apiDoc += doc.doc.replace(/\s*\*\s*/g, '\n') + '\n\n';
}
apiDoc += '\n---\n🤖 Generated by BlackRoad Bot System\n';
apiDoc += '🎨 Visuals by Canva Integration\n';
fs.writeFileSync('API.md', apiDoc);
core.setOutput('docs_generated', 'true');
core.setOutput('function_count', docs.length);
console.log(`Generated API documentation with ${docs.length} functions`);
} else {
core.setOutput('docs_generated', 'false');
}
}
- name: Generate architecture diagram with Canva
if: steps.gen_docs.outputs.docs_generated == 'true'
env:
CANVA_ACCESS_TOKEN: ${{ secrets.CANVA_ACCESS_TOKEN }}
run: |
python3 << 'PYTHON_SCRIPT'
import os
import json
import sys
# Check if Canva integration is available
canva_client_path = os.path.expanduser('~/canva-integration/canva_client.py')
if not os.path.exists(canva_client_path):
print("⚠️ Canva integration not found")
print("Skipping diagram generation")
sys.exit(0)
# Add canva-integration to path
sys.path.insert(0, os.path.expanduser('~/canva-integration'))
try:
from canva_client import CanvaClient
except ImportError:
print("⚠️ Cannot import CanvaClient")
print("Skipping diagram generation")
sys.exit(0)
# Load diagram request
with open('canva-diagram-request.json', 'r') as f:
request = json.load(f)
print(f"📊 Creating architecture diagram for {request['repository']}")
print(f" Functions: {request['functionCount']}")
# Initialize Canva client
access_token = os.environ.get('CANVA_ACCESS_TOKEN')
if not access_token:
print("⚠️ CANVA_ACCESS_TOKEN not set")
print("Skipping diagram generation")
sys.exit(0)
client = CanvaClient(access_token=access_token)
# Create design (architecture diagram template)
design_data = {
"design_type": "Poster",
"title": f"{request['repository']} Architecture"
}
try:
design = client.create_design(design_data)
design_id = design.get('design', {}).get('id')
print(f"✅ Created Canva design: {design_id}")
# Export as PNG
export_data = {
"format": "png"
}
export_result = client.export_design(design_id, export_data)
export_url = export_result.get('export', {}).get('url')
if export_url:
print(f"✅ Diagram exported: {export_url}")
# Download diagram
import urllib.request
urllib.request.urlretrieve(export_url, 'architecture-diagram.png')
print("✅ Diagram downloaded to architecture-diagram.png")
else:
print("⚠️ No export URL received")
except Exception as e:
print(f"⚠️ Canva API error: {e}")
print("Continuing without diagram")
PYTHON_SCRIPT
- name: Update README with diagram
if: steps.gen_docs.outputs.docs_generated == 'true'
run: |
if [ -f architecture-diagram.png ]; then
# Add diagram to README
if [ -f README.md ]; then
# Check if diagram section exists
if ! grep -q "## Architecture" README.md; then
echo "" >> README.md
echo "## Architecture" >> README.md
echo "" >> README.md
echo "![Architecture Diagram](./architecture-diagram.png)" >> README.md
echo "" >> README.md
echo "🎨 *Auto-generated by Canva Integration*" >> README.md
fi
fi
fi
- name: Create PR with visual docs
uses: actions/github-script@v7
with:
script: |
const { execSync } = require('child_process');
const status = execSync('git status --porcelain').toString();
if (status.trim()) {
const branchName = `bot/docs-with-visuals-${Date.now()}`;
execSync(`git config user.name "BlackRoad Bot"`);
execSync(`git config user.email "bot@blackroad.io"`);
execSync(`git checkout -b ${branchName}`);
execSync(`git add .`);
execSync(`git commit -m "🤖 docs: Auto-update documentation with visual diagrams
- Generated API documentation
- Created architecture diagram via Canva
- Updated README with visuals
Generated by: BlackRoad Bot System + Canva Integration"`);
execSync(`git push origin ${branchName}`);
await github.rest.pulls.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: '🤖 🎨 docs: Auto-update documentation with visuals',
body: `## Documentation Updates with Visuals
This PR includes automated documentation updates with visual diagrams:
- ✅ API documentation generation
- ✅ Architecture diagram (Canva-generated)
- ✅ README improvements
- ✅ Visual assets
**Generated by:**
- BlackRoad Bot System (documentation)
- Canva Integration (visuals)
**Functions documented:** ${steps.gen_docs.outputs.function_count || 0}
cc: @${context.repo.owner}`,
head: branchName,
base: 'main'
});
}
- name: Log to memory
run: |
if [ -f ~/memory-system.sh ]; then
~/memory-system.sh log bot-action "docs-with-canva" "Generated visual docs for ${{ github.repository }}: ${steps.gen_docs.outputs.function_count || 0} functions documented with Canva diagrams"
fi

199
bot-docs-update.yml Normal file
View File

@@ -0,0 +1,199 @@
name: Bot - Documentation Update
on:
push:
branches: [main, master]
paths:
- 'src/**'
- 'lib/**'
- '*.md'
schedule:
- cron: '0 0 * * 1' # Weekly on Monday
permissions:
contents: write
pull-requests: write
jobs:
update-docs:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Check README exists
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
if (!fs.existsSync('README.md')) {
const template = `# ${context.repo.repo}
## Overview
[Add project description]
## Installation
\`\`\`bash
npm install
\`\`\`
## Usage
[Add usage instructions]
## Contributing
See CONTRIBUTING.md
## License
[Add license]
---
🤖 Generated by BlackRoad Bot System
`;
fs.writeFileSync('README.md', template);
await github.rest.repos.createOrUpdateFileContents({
owner: context.repo.owner,
repo: context.repo.repo,
path: 'README.md',
message: '🤖 docs: Add README template',
content: Buffer.from(template).toString('base64')
});
}
- name: Generate API docs
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const path = require('path');
// Simple JSDoc extraction
function extractDocs(filePath) {
const content = fs.readFileSync(filePath, 'utf8');
const docRegex = /\/\*\*([\s\S]*?)\*\/\s*(?:export\s+)?(?:async\s+)?function\s+(\w+)/g;
const docs = [];
let match;
while ((match = docRegex.exec(content)) !== null) {
docs.push({
name: match[2],
doc: match[1].trim()
});
}
return docs;
}
function scanForFunctions(dir) {
const docs = [];
const entries = fs.readdirSync(dir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(dir, entry.name);
if (entry.name.startsWith('.') || entry.name === 'node_modules') {
continue;
}
if (entry.isDirectory()) {
docs.push(...scanForFunctions(fullPath));
} else if (entry.name.endsWith('.js') || entry.name.endsWith('.ts')) {
docs.push(...extractDocs(fullPath));
}
}
return docs;
}
if (fs.existsSync('src')) {
const docs = scanForFunctions('src');
if (docs.length > 0) {
let apiDoc = '# API Documentation\n\n';
apiDoc += '> Auto-generated from source code\n\n';
for (const doc of docs) {
apiDoc += `## ${doc.name}\n\n`;
apiDoc += doc.doc.replace(/\s*\*\s*/g, '\n') + '\n\n';
}
apiDoc += '\n---\n🤖 Generated by BlackRoad Bot System\n';
fs.writeFileSync('API.md', apiDoc);
console.log(`Generated API documentation with ${docs.length} functions`);
}
}
- name: Update documentation links
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
if (fs.existsSync('README.md')) {
let readme = fs.readFileSync('README.md', 'utf8');
// Add links section if missing
if (!readme.includes('## Links') && !readme.includes('## Resources')) {
const links = `
## Links
- [Documentation](https://docs.blackroad.io)
- [API Reference](./API.md)
- [Contributing](./CONTRIBUTING.md)
- [BlackRoad OS](https://github.com/BlackRoad-OS)
`;
readme += links;
fs.writeFileSync('README.md', readme);
}
}
- name: Create PR for doc updates
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
// Check if we made changes
const { execSync } = require('child_process');
const status = execSync('git status --porcelain').toString();
if (status.trim()) {
const branchName = `bot/docs-update-${Date.now()}`;
execSync(`git config user.name "BlackRoad Bot"`);
execSync(`git config user.email "bot@blackroad.io"`);
execSync(`git checkout -b ${branchName}`);
execSync(`git add .`);
execSync(`git commit -m "🤖 docs: Auto-update documentation"`);
execSync(`git push origin ${branchName}`);
await github.rest.pulls.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: '🤖 docs: Auto-update documentation',
body: `## Documentation Updates
This PR includes automated documentation updates:
- README improvements
- API documentation generation
- Link updates
**Generated by:** BlackRoad Bot System
**Review:** Please verify changes before merging
cc: @${context.repo.owner}`,
head: branchName,
base: 'main'
});
}
- name: Log to memory
run: |
if [ -f ~/memory-system.sh ]; then
~/memory-system.sh log bot-action "docs-update" "Documentation updated for ${{ github.repository }}"
fi

122
bot-issue-triage.yml Normal file
View File

@@ -0,0 +1,122 @@
name: Bot - Issue Triage
on:
issues:
types: [opened, edited, reopened]
permissions:
issues: write
contents: read
jobs:
triage:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Auto-label issue
uses: actions/github-script@v7
with:
script: |
const issue = context.payload.issue;
const title = issue.title.toLowerCase();
const body = issue.body ? issue.body.toLowerCase() : '';
const labels = [];
// Auto-detect issue type
if (title.includes('bug') || body.includes('error') || body.includes('broken')) {
labels.push('bug');
}
if (title.includes('feature') || title.includes('enhancement')) {
labels.push('enhancement');
}
if (title.includes('docs') || title.includes('documentation')) {
labels.push('documentation');
}
if (title.includes('security') || body.includes('vulnerability')) {
labels.push('security');
}
if (title.includes('performance') || body.includes('slow')) {
labels.push('performance');
}
if (title.includes('test')) {
labels.push('testing');
}
// Priority detection
if (title.includes('urgent') || title.includes('critical') || body.includes('production down')) {
labels.push('priority:high');
} else if (title.includes('minor') || title.includes('trivial')) {
labels.push('priority:low');
} else {
labels.push('priority:medium');
}
// Add labels
if (labels.length > 0) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
labels: labels
});
}
// Add triage comment
const comment = `👋 Thanks for opening this issue!
🤖 **Bot Triage:**
- Auto-labeled as: ${labels.join(', ')}
- Assigned priority based on content
- A team member will review soon
This is an automated message from the BlackRoad bot system.`;
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: comment
});
- name: Check for duplicates
uses: actions/github-script@v7
with:
script: |
const issue = context.payload.issue;
const title = issue.title.toLowerCase();
// Search for similar issues
const { data: issues } = await github.rest.issues.listForRepo({
owner: context.repo.owner,
repo: context.repo.repo,
state: 'all',
per_page: 100
});
const similar = issues.filter(i =>
i.number !== issue.number &&
i.title.toLowerCase().includes(title.split(' ')[0])
);
if (similar.length > 0) {
const duplicateList = similar.slice(0, 5).map(i => `- #${i.number}: ${i.title}`).join('\n');
await github.rest.issues.createComment({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: issue.number,
body: `🤖 **Possible Duplicates Detected:**
${duplicateList}
Please check if any of these issues match your report.`
});
}
- name: Log to memory
run: |
if [ -f ~/memory-system.sh ]; then
~/memory-system.sh log bot-action "issue-triage" "Triaged issue #${{ github.event.issue.number }} in ${{ github.repository }}"
fi

171
bot-pr-review.yml Normal file
View File

@@ -0,0 +1,171 @@
name: Bot - PR Review
on:
pull_request:
types: [opened, synchronize, reopened]
permissions:
contents: read
pull-requests: write
checks: write
jobs:
review:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Auto-label PR
uses: actions/github-script@v7
with:
script: |
const pr = context.payload.pull_request;
const title = pr.title.toLowerCase();
const labels = [];
// Detect PR type from title
if (title.startsWith('feat:') || title.startsWith('feature:')) {
labels.push('feature');
}
if (title.startsWith('fix:') || title.startsWith('bugfix:')) {
labels.push('bugfix');
}
if (title.startsWith('docs:')) {
labels.push('documentation');
}
if (title.startsWith('refactor:')) {
labels.push('refactoring');
}
if (title.startsWith('test:')) {
labels.push('testing');
}
if (title.startsWith('chore:')) {
labels.push('chore');
}
// Size labels
const changedFiles = pr.changed_files;
if (changedFiles <= 5) {
labels.push('size:small');
} else if (changedFiles <= 20) {
labels.push('size:medium');
} else {
labels.push('size:large');
}
if (labels.length > 0) {
await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.number,
labels: labels
});
}
- name: Check PR description
uses: actions/github-script@v7
with:
script: |
const pr = context.payload.pull_request;
const body = pr.body || '';
if (body.length < 50) {
await github.rest.pulls.createReview({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pr.number,
event: 'COMMENT',
body: `🤖 **Bot Review Notice:**
⚠️ This PR has a short description. Please add:
- What does this PR do?
- Why is this change needed?
- How was it tested?
A detailed description helps reviewers understand your changes.`
});
}
- name: Analyze code changes
uses: actions/github-script@v7
with:
script: |
const pr = context.payload.pull_request;
// Get files changed
const { data: files } = await github.rest.pulls.listFiles({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pr.number
});
const insights = [];
// Check for common patterns
const hasTests = files.some(f => f.filename.includes('test') || f.filename.includes('spec'));
const hasDocs = files.some(f => f.filename.endsWith('.md'));
const hasConfig = files.some(f => f.filename.includes('config') || f.filename.endsWith('.json') || f.filename.endsWith('.yml'));
if (!hasTests && files.length > 3) {
insights.push('⚠️ No test files detected. Consider adding tests for your changes.');
}
if (files.length > 50) {
insights.push('⚠️ Large PR detected (50+ files). Consider breaking into smaller PRs.');
}
const secretPatterns = [
/api[_-]?key/i,
/secret/i,
/password/i,
/token/i,
/credential/i
];
for (const file of files) {
if (file.patch) {
for (const pattern of secretPatterns) {
if (pattern.test(file.patch)) {
insights.push(`🔒 Possible secret detected in ${file.filename}. Please verify no credentials are committed.`);
break;
}
}
}
}
if (insights.length > 0) {
await github.rest.pulls.createReview({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pr.number,
event: 'COMMENT',
body: `🤖 **Bot Code Review:**
${insights.join('\n\n')}
This is an automated review. A human will review your changes soon.`
});
} else {
await github.rest.pulls.createReview({
owner: context.repo.owner,
repo: context.repo.repo,
pull_number: pr.number,
event: 'COMMENT',
body: `🤖 **Bot Code Review:**
✅ No issues detected in automated review
✅ Code changes look good
✅ Ready for human review
This is an automated review.`
});
}
- name: Log to memory
run: |
if [ -f ~/memory-system.sh ]; then
~/memory-system.sh log bot-action "pr-review" "Reviewed PR #${{ github.event.pull_request.number }} in ${{ github.repository }}"
fi

196
bot-release.yml Normal file
View File

@@ -0,0 +1,196 @@
name: Bot - Release Automation
on:
push:
branches: [main, master]
workflow_dispatch:
inputs:
release_type:
description: 'Release type'
required: true
type: choice
options:
- patch
- minor
- major
permissions:
contents: write
pull-requests: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Detect version bump
id: version
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const { execSync } = require('child_process');
// Check for package.json
if (!fs.existsSync('package.json')) {
console.log('No package.json, skipping release');
return { shouldRelease: false };
}
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
const currentVersion = pkg.version || '0.0.0';
// Get recent commits
const commits = execSync('git log --oneline -20').toString();
// Detect version bump type from commits
let bumpType = 'patch';
if (commits.match(/BREAKING CHANGE|!:/)) {
bumpType = 'major';
} else if (commits.match(/^feat:|^feature:/m)) {
bumpType = 'minor';
}
// Override with manual input if provided
if (context.payload.inputs?.release_type) {
bumpType = context.payload.inputs.release_type;
}
core.setOutput('bump_type', bumpType);
core.setOutput('current_version', currentVersion);
core.setOutput('should_release', 'true');
return { shouldRelease: true, bumpType, currentVersion };
- name: Bump version
if: steps.version.outputs.should_release == 'true'
id: bump
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
const currentVersion = pkg.version || '0.0.0';
const bumpType = '${{ steps.version.outputs.bump_type }}';
// Simple semver bump
const [major, minor, patch] = currentVersion.split('.').map(Number);
let newVersion;
if (bumpType === 'major') {
newVersion = `${major + 1}.0.0`;
} else if (bumpType === 'minor') {
newVersion = `${major}.${minor + 1}.0`;
} else {
newVersion = `${major}.${minor}.${patch + 1}`;
}
pkg.version = newVersion;
fs.writeFileSync('package.json', JSON.stringify(pkg, null, 2) + '\n');
core.setOutput('new_version', newVersion);
return { newVersion };
- name: Generate changelog
if: steps.version.outputs.should_release == 'true'
id: changelog
uses: actions/github-script@v7
with:
script: |
const { execSync } = require('child_process');
// Get commits since last tag
let commits;
try {
const lastTag = execSync('git describe --tags --abbrev=0').toString().trim();
commits = execSync(`git log ${lastTag}..HEAD --oneline`).toString();
} catch {
// No previous tags
commits = execSync('git log --oneline').toString();
}
const lines = commits.split('\n').filter(l => l.trim());
const features = lines.filter(l => l.match(/feat:|feature:/i));
const fixes = lines.filter(l => l.match(/fix:|bugfix:/i));
const chores = lines.filter(l => l.match(/chore:|refactor:/i));
const docs = lines.filter(l => l.match(/docs:|documentation:/i));
let changelog = `# Changelog\n\n`;
changelog += `## Version ${{ steps.bump.outputs.new_version }}\n\n`;
if (features.length > 0) {
changelog += `### Features\n`;
features.forEach(f => changelog += `- ${f.replace(/^[a-f0-9]+\s+/, '')}\n`);
changelog += '\n';
}
if (fixes.length > 0) {
changelog += `### Bug Fixes\n`;
fixes.forEach(f => changelog += `- ${f.replace(/^[a-f0-9]+\s+/, '')}\n`);
changelog += '\n';
}
if (docs.length > 0) {
changelog += `### Documentation\n`;
docs.forEach(d => changelog += `- ${d.replace(/^[a-f0-9]+\s+/, '')}\n`);
changelog += '\n';
}
if (chores.length > 0) {
changelog += `### Other Changes\n`;
chores.forEach(c => changelog += `- ${c.replace(/^[a-f0-9]+\s+/, '')}\n`);
changelog += '\n';
}
changelog += `---\n🤖 Generated by BlackRoad Bot System\n`;
core.setOutput('changelog', changelog);
return { changelog };
- name: Create release
if: steps.version.outputs.should_release == 'true'
uses: actions/github-script@v7
with:
script: |
const { execSync } = require('child_process');
const newVersion = '${{ steps.bump.outputs.new_version }}';
const changelog = `${{ steps.changelog.outputs.changelog }}`;
// Commit version bump
execSync(`git config user.name "BlackRoad Bot"`);
execSync(`git config user.email "bot@blackroad.io"`);
execSync(`git add package.json`);
execSync(`git commit -m "🤖 chore: Bump version to ${newVersion}"`);
// Create tag
execSync(`git tag -a v${newVersion} -m "Release v${newVersion}"`);
execSync(`git push origin main --tags`);
// Create GitHub release
await github.rest.repos.createRelease({
owner: context.repo.owner,
repo: context.repo.repo,
tag_name: `v${newVersion}`,
name: `Release v${newVersion}`,
body: changelog,
draft: false,
prerelease: false
});
console.log(`✅ Released v${newVersion}`);
- name: Log to memory
run: |
if [ -f ~/memory-system.sh ]; then
~/memory-system.sh log bot-action "release" "Released version ${{ steps.bump.outputs.new_version }} for ${{ github.repository }}"
fi

149
bot-security-scan.yml Normal file
View File

@@ -0,0 +1,149 @@
name: Bot - Security Scan
on:
push:
branches: [main, master, develop]
pull_request:
branches: [main, master, develop]
schedule:
- cron: '0 0 * * 0' # Weekly on Sunday
permissions:
contents: read
security-events: write
issues: write
jobs:
security-scan:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Secret scanning
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const path = require('path');
const secretPatterns = [
{ name: 'API Key', pattern: /(?:api[_-]?key|apikey)[\s:=]+['"]?([a-zA-Z0-9_-]{20,})['"]?/gi },
{ name: 'Password', pattern: /(?:password|passwd|pwd)[\s:=]+['"]?([^\s'"]{8,})['"]?/gi },
{ name: 'Token', pattern: /(?:token|auth[_-]?token)[\s:=]+['"]?([a-zA-Z0-9_-]{20,})['"]?/gi },
{ name: 'Private Key', pattern: /-----BEGIN (?:RSA |EC )?PRIVATE KEY-----/gi },
{ name: 'AWS Key', pattern: /AKIA[0-9A-Z]{16}/gi },
{ name: 'GitHub Token', pattern: /gh[ps]_[a-zA-Z0-9]{36,}/gi }
];
const findings = [];
function scanDirectory(dir) {
const entries = fs.readdirSync(dir, { withFileTypes: true });
for (const entry of entries) {
const fullPath = path.join(dir, entry.name);
// Skip node_modules, .git, etc.
if (entry.name.startsWith('.') || entry.name === 'node_modules') {
continue;
}
if (entry.isDirectory()) {
scanDirectory(fullPath);
} else if (entry.isFile()) {
try {
const content = fs.readFileSync(fullPath, 'utf8');
for (const { name, pattern } of secretPatterns) {
const matches = content.match(pattern);
if (matches) {
findings.push({
type: name,
file: fullPath,
count: matches.length
});
}
}
} catch (err) {
// Skip binary files
}
}
}
}
scanDirectory('.');
if (findings.length > 0) {
const message = `🚨 **Security Alert: Potential Secrets Detected**
${findings.map(f => `- **${f.type}** found in \`${f.file}\` (${f.count} occurrence${f.count > 1 ? 's' : ''})`).join('\n')}
⚠️ **Action Required:**
1. Verify if these are real secrets
2. If yes, rotate credentials immediately
3. Remove from git history
4. Use environment variables instead
cc: @${context.repo.owner}`;
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: '🚨 Security: Potential Secrets Detected',
body: message,
labels: ['security', 'priority:high']
});
core.setFailed('Potential secrets detected!');
}
- name: Dependency scan
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
// Check for package.json
if (fs.existsSync('package.json')) {
const pkg = JSON.parse(fs.readFileSync('package.json', 'utf8'));
const deps = { ...pkg.dependencies, ...pkg.devDependencies };
const outdatedWarnings = [];
// Known vulnerable package patterns (simplified)
const knownVulnerable = ['event-stream@3.3.6', 'lodash@<4.17.21'];
for (const [name, version] of Object.entries(deps)) {
const fullDep = `${name}@${version}`;
if (knownVulnerable.some(v => fullDep.includes(v))) {
outdatedWarnings.push(`⚠️ ${name}@${version} has known vulnerabilities`);
}
}
if (outdatedWarnings.length > 0) {
await github.rest.issues.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: '🔒 Security: Vulnerable Dependencies Detected',
body: `**Vulnerable dependencies found:**\n\n${outdatedWarnings.join('\n')}\n\nPlease update to secure versions.`,
labels: ['security', 'dependencies']
});
}
}
- name: CodeQL Analysis
uses: github/codeql-action/init@v3
with:
languages: javascript, python, typescript
continue-on-error: true
- name: Run CodeQL
uses: github/codeql-action/analyze@v3
continue-on-error: true
- name: Log to memory
run: |
if [ -f ~/memory-system.sh ]; then
~/memory-system.sh log bot-action "security-scan" "Security scan completed for ${{ github.repository }}"
fi

191
bot-sync.yml Normal file
View File

@@ -0,0 +1,191 @@
name: Bot - Workflow Sync
on:
workflow_dispatch:
schedule:
- cron: '0 0 * * 1' # Weekly on Monday
permissions:
contents: write
pull-requests: write
jobs:
sync-workflows:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Sync bot workflows
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
// Ensure .github/workflows exists
if (!fs.existsSync('.github/workflows')) {
fs.mkdirSync('.github/workflows', { recursive: true });
}
// Standard labels for all repos
const standardLabels = [
{ name: 'bug', color: 'd73a4a', description: 'Something isn\'t working' },
{ name: 'enhancement', color: 'a2eeef', description: 'New feature or request' },
{ name: 'documentation', color: '0075ca', description: 'Improvements or additions to documentation' },
{ name: 'security', color: 'ff0000', description: 'Security vulnerability or concern' },
{ name: 'performance', color: 'ff9800', description: 'Performance improvement' },
{ name: 'testing', color: '4caf50', description: 'Testing related' },
{ name: 'priority:high', color: 'b60205', description: 'High priority' },
{ name: 'priority:medium', color: 'fbca04', description: 'Medium priority' },
{ name: 'priority:low', color: '0e8a16', description: 'Low priority' },
{ name: 'size:small', color: 'c5def5', description: 'Small PR (1-5 files)' },
{ name: 'size:medium', color: '7fb8d8', description: 'Medium PR (6-20 files)' },
{ name: 'size:large', color: '0052cc', description: 'Large PR (20+ files)' }
];
// Create/update labels
for (const label of standardLabels) {
try {
await github.rest.issues.createLabel({
owner: context.repo.owner,
repo: context.repo.repo,
name: label.name,
color: label.color,
description: label.description
});
} catch (err) {
if (err.status === 422) {
// Label exists, update it
await github.rest.issues.updateLabel({
owner: context.repo.owner,
repo: context.repo.repo,
name: label.name,
color: label.color,
description: label.description
});
}
}
}
console.log('✅ Synced standard labels');
- name: Sync bot config
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const yaml = require('js-yaml');
const botConfig = {
bots: {
issue_triage: {
enabled: true,
auto_label: true,
assign_team: true,
detect_duplicates: true
},
pr_review: {
enabled: true,
require_tests: true,
security_scan: true,
code_quality: true
},
security: {
enabled: true,
dependabot: true,
secret_scan: true,
codeql: true
},
documentation: {
enabled: true,
auto_generate: true,
sync_readme: true
},
sync: {
enabled: true,
workflow_sync: true,
config_sync: true
}
},
organization: 'BlackRoad-OS',
contact: 'blackroad.systems@gmail.com'
};
if (!fs.existsSync('.github')) {
fs.mkdirSync('.github');
}
fs.writeFileSync('.github/bot-config.yml', yaml.dump(botConfig));
console.log('✅ Created bot config');
- name: Sync CODEOWNERS
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
const codeowners = `# BlackRoad OS Code Owners
# Auto-synced by bot system
# Default owners for everything in the repo
* @${context.repo.owner}
# Specific paths
/.github/ @${context.repo.owner}
/docs/ @${context.repo.owner}
# Auto-generated by BlackRoad Bot System
`;
if (!fs.existsSync('.github')) {
fs.mkdirSync('.github');
}
fs.writeFileSync('.github/CODEOWNERS', codeowners);
console.log('✅ Synced CODEOWNERS');
- name: Create sync PR
uses: actions/github-script@v7
with:
script: |
const { execSync } = require('child_process');
const status = execSync('git status --porcelain').toString();
if (status.trim()) {
const branchName = `bot/sync-${Date.now()}`;
execSync(`git config user.name "BlackRoad Bot"`);
execSync(`git config user.email "bot@blackroad.io"`);
execSync(`git checkout -b ${branchName}`);
execSync(`git add .`);
execSync(`git commit -m "🤖 chore: Sync bot workflows and config"`);
execSync(`git push origin ${branchName}`);
await github.rest.pulls.create({
owner: context.repo.owner,
repo: context.repo.repo,
title: '🤖 chore: Sync bot workflows and config',
body: `## Bot System Sync
This PR syncs the repository with org-wide standards:
- ✅ Standard labels
- ✅ Bot configuration
- ✅ CODEOWNERS file
**Auto-generated by:** BlackRoad Bot System
Safe to merge after review.`,
head: branchName,
base: 'main'
});
} else {
console.log('✅ Everything already in sync');
}
- name: Log to memory
run: |
if [ -f ~/memory-system.sh ]; then
~/memory-system.sh log bot-action "workflow-sync" "Synced workflows for ${{ github.repository }}"
fi