mirror of
https://github.com/browseros-ai/BrowserOS.git
synced 2026-05-13 15:46:22 +00:00
feat: new workflows (#470)
This commit is contained in:
192
.github/workflows/audit.yml
vendored
Normal file
192
.github/workflows/audit.yml
vendored
Normal file
@@ -0,0 +1,192 @@
|
||||
name: Daily Security Audit
|
||||
|
||||
on:
|
||||
schedule:
|
||||
# Runs at midnight IST (6:30 PM UTC previous day)
|
||||
- cron: "30 18 * * *"
|
||||
workflow_dispatch: # Allows manual triggering
|
||||
|
||||
jobs:
|
||||
security-audit:
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: packages/browseros-agent
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun ci
|
||||
|
||||
- name: Run security audit
|
||||
id: audit
|
||||
continue-on-error: true
|
||||
run: |
|
||||
# Run audit and capture output (skip the version line)
|
||||
bun audit --json 2>&1 | tail -n 1 > audit-results.json || true
|
||||
|
||||
# Check if vulnerabilities exist
|
||||
VULN_COUNT=$(cat audit-results.json | bun -e "const data = JSON.parse(require('fs').readFileSync(0, 'utf-8')); console.log(Object.keys(data).reduce((sum, pkg) => sum + data[pkg].length, 0))")
|
||||
echo "vuln_count=$VULN_COUNT" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Parse audit results
|
||||
id: parse
|
||||
if: always()
|
||||
run: |
|
||||
cat > parse-audit.ts << 'EOF'
|
||||
const fs = require('fs');
|
||||
const auditData = JSON.parse(fs.readFileSync('audit-results.json', 'utf-8'));
|
||||
|
||||
// Collect all vulnerabilities from all packages
|
||||
const allVulns: any[] = [];
|
||||
let totalCount = 0;
|
||||
|
||||
for (const [packageName, vulns] of Object.entries(auditData)) {
|
||||
if (Array.isArray(vulns)) {
|
||||
vulns.forEach((vuln: any) => {
|
||||
allVulns.push({ ...vuln, packageName });
|
||||
totalCount++;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (totalCount === 0) {
|
||||
console.log(JSON.stringify({
|
||||
text: "✅ *Daily Security Audit - No Vulnerabilities Found*",
|
||||
blocks: [
|
||||
{
|
||||
type: "section",
|
||||
text: {
|
||||
type: "mrkdwn",
|
||||
text: "✅ *Daily Security Audit*\n\nNo vulnerabilities found in dependencies!"
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "context",
|
||||
elements: [
|
||||
{
|
||||
type: "mrkdwn",
|
||||
text: `Repository: ${process.env.GITHUB_REPOSITORY} | Branch: ${process.env.GITHUB_REF_NAME}`
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}));
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
// Count by severity
|
||||
const severityCounts = {
|
||||
critical: 0,
|
||||
high: 0,
|
||||
moderate: 0,
|
||||
low: 0
|
||||
};
|
||||
|
||||
allVulns.forEach(vuln => {
|
||||
severityCounts[vuln.severity as keyof typeof severityCounts]++;
|
||||
});
|
||||
|
||||
let message = `⚠️ *Daily Security Audit - ${totalCount} Vulnerabilit${totalCount === 1 ? 'y' : 'ies'} Found*\n\n`;
|
||||
message += `*Severity Breakdown:*\n`;
|
||||
message += `• Critical: ${severityCounts.critical}\n`;
|
||||
message += `• High: ${severityCounts.high}\n`;
|
||||
message += `• Moderate: ${severityCounts.moderate}\n`;
|
||||
message += `• Low: ${severityCounts.low}\n\n`;
|
||||
|
||||
message += `*Top Vulnerabilities:*\n`;
|
||||
|
||||
// Sort by severity
|
||||
const severityOrder = { critical: 0, high: 1, moderate: 2, low: 3 };
|
||||
allVulns.sort((a, b) =>
|
||||
severityOrder[a.severity as keyof typeof severityOrder] -
|
||||
severityOrder[b.severity as keyof typeof severityOrder]
|
||||
);
|
||||
|
||||
allVulns.slice(0, 5).forEach(vuln => {
|
||||
const emoji = {
|
||||
critical: '🔴',
|
||||
high: '🟠',
|
||||
moderate: '🟡',
|
||||
low: '🟢'
|
||||
}[vuln.severity] || '⚪';
|
||||
|
||||
message += `\n${emoji} *${vuln.title}*\n`;
|
||||
message += ` Package: \`${vuln.packageName}\`\n`;
|
||||
message += ` Severity: ${vuln.severity.toUpperCase()}\n`;
|
||||
message += ` Vulnerable: ${vuln.vulnerable_versions}\n`;
|
||||
if (vuln.cwe?.length) {
|
||||
message += ` CWE: ${vuln.cwe.join(', ')}\n`;
|
||||
}
|
||||
if (vuln.cvss?.score) {
|
||||
message += ` CVSS: ${vuln.cvss.score}\n`;
|
||||
}
|
||||
if (vuln.url) {
|
||||
message += ` <${vuln.url}|View Details>\n`;
|
||||
}
|
||||
});
|
||||
|
||||
if (allVulns.length > 5) {
|
||||
message += `\n_...and ${allVulns.length - 5} more vulnerabilit${allVulns.length - 5 === 1 ? 'y' : 'ies'}_`;
|
||||
}
|
||||
|
||||
const payload = {
|
||||
text: `⚠️ Security Audit: ${totalCount} vulnerabilit${totalCount === 1 ? 'y' : 'ies'} found`,
|
||||
blocks: [
|
||||
{
|
||||
type: "section",
|
||||
text: {
|
||||
type: "mrkdwn",
|
||||
text: message
|
||||
}
|
||||
},
|
||||
{
|
||||
type: "actions",
|
||||
elements: [
|
||||
{
|
||||
type: "button",
|
||||
text: {
|
||||
type: "plain_text",
|
||||
text: "View Full Report"
|
||||
},
|
||||
url: `https://github.com/${process.env.GITHUB_REPOSITORY}/actions/runs/${process.env.GITHUB_RUN_ID}`
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
type: "context",
|
||||
elements: [
|
||||
{
|
||||
type: "mrkdwn",
|
||||
text: `Repository: ${process.env.GITHUB_REPOSITORY} | Branch: ${process.env.GITHUB_REF_NAME}`
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
};
|
||||
|
||||
console.log(JSON.stringify(payload));
|
||||
EOF
|
||||
|
||||
bun run parse-audit.ts > slack-payload.json
|
||||
|
||||
- name: Send to Slack
|
||||
if: always()
|
||||
env:
|
||||
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK_URL }}
|
||||
run: |
|
||||
curl -X POST \
|
||||
-H 'Content-Type: application/json' \
|
||||
-d @slack-payload.json \
|
||||
$SLACK_WEBHOOK_URL
|
||||
|
||||
- name: Fail if vulnerabilities found
|
||||
if: steps.audit.outputs.vuln_count != '0'
|
||||
run: |
|
||||
echo "Security audit found vulnerabilities"
|
||||
exit 1
|
||||
17
.github/workflows/branch-cleaner.yml
vendored
Normal file
17
.github/workflows/branch-cleaner.yml
vendored
Normal file
@@ -0,0 +1,17 @@
|
||||
name: GitHub Branch Cleaner
|
||||
|
||||
on:
|
||||
schedule:
|
||||
- cron: '0 0 * * 0'
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
cleanup:
|
||||
name: Clean up merged branches
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: mmorenoregalado/action-branches-cleaner@v2.0.3
|
||||
with:
|
||||
token: ${{ secrets.GITHUB_TOKEN }}
|
||||
base_branches: main
|
||||
days_old_threshold: 30
|
||||
65
.github/workflows/cla.yml
vendored
65
.github/workflows/cla.yml
vendored
@@ -1,11 +1,11 @@
|
||||
name: 'CLA Assistant'
|
||||
name: CLA Assistant
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
pull_request_target:
|
||||
types: [opened, closed, synchronize]
|
||||
|
||||
# Explicitly configure permissions
|
||||
permissions:
|
||||
actions: write
|
||||
contents: write
|
||||
@@ -13,47 +13,46 @@ permissions:
|
||||
statuses: write
|
||||
|
||||
jobs:
|
||||
CLAAssistant:
|
||||
cla:
|
||||
runs-on: ubuntu-latest
|
||||
if: |
|
||||
(github.event_name == 'pull_request_target') ||
|
||||
(github.event_name == 'issue_comment' && github.event.issue.pull_request &&
|
||||
(github.event.comment.body == 'recheck' ||
|
||||
github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA'))
|
||||
steps:
|
||||
- name: 'CLA Assistant'
|
||||
if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target'
|
||||
- name: CLA Assistant
|
||||
uses: contributor-assistant/github-action@v2.6.1
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
PERSONAL_ACCESS_TOKEN: ${{ secrets.CLA_SIGNATURES_TOKEN }}
|
||||
with:
|
||||
# Path where signatures will be stored
|
||||
path-to-signatures: 'signatures/version1/cla.json'
|
||||
|
||||
# Path to your CLA document
|
||||
path-to-document: 'https://github.com/browseros-ai/BrowserOS/blob/main/CLA.md'
|
||||
|
||||
# Branch to store signatures (should not be protected)
|
||||
path-to-signatures: 'cla-signatures.json'
|
||||
path-to-document: 'https://github.com/${{ github.repository }}/blob/main/CLA.md'
|
||||
branch: 'main'
|
||||
|
||||
# Allowlist for users who don't need to sign (bots, core team members)
|
||||
allowlist: shadowfax92,felarof99,dependabot[bot],renovate[bot],github-actions[bot]
|
||||
|
||||
# Optional: Custom messages
|
||||
remote-organization-name: 'browseros-ai'
|
||||
remote-repository-name: 'cla-signatures'
|
||||
allowlist: 'shadowfax92,felarof99,bot*,*[bot],dependabot,renovate,github-actions,snyk-bot,imgbot,greenkeeper,semantic-release-bot,allcontributors'
|
||||
lock-pullrequest-aftermerge: false
|
||||
custom-notsigned-prcomment: |
|
||||
**CLA Assistant Lite bot** Thank you for your submission! We require contributors to sign our [Contributor License Agreement](https://github.com/browseros-ai/BrowserOS/blob/main/CLA.md) before we can accept your contribution.
|
||||
Thank you for your contribution! Before we can merge this PR, we need you to sign our [Contributor License Agreement](https://github.com/${{ github.repository }}/blob/main/CLA.md).
|
||||
|
||||
By signing the CLA, you confirm that:
|
||||
- You have read and agree to the AGPL-3.0 license terms
|
||||
- Your contribution is your original work
|
||||
- You grant us the rights to use your contribution under the AGPL-3.0 license
|
||||
**To sign the CLA**, please add a comment to this PR with the following text:
|
||||
|
||||
**To sign the CLA, please comment on this PR with:**
|
||||
`I have read the CLA Document and I hereby sign the CLA`
|
||||
```
|
||||
I have read the CLA Document and I hereby sign the CLA
|
||||
```
|
||||
|
||||
You only need to sign once. After signing, this check will pass automatically.
|
||||
|
||||
---
|
||||
<details>
|
||||
<summary>Troubleshooting</summary>
|
||||
|
||||
- **Already signed but still failing?** Comment `recheck` to trigger a re-verification.
|
||||
- **Signed with a different email?** Make sure your commit email matches your GitHub account email, or add your commit email to your GitHub account.
|
||||
|
||||
</details>
|
||||
custom-pr-sign-comment: 'I have read the CLA Document and I hereby sign the CLA'
|
||||
|
||||
custom-allsigned-prcomment: |
|
||||
**CLA Assistant Lite bot** ✅ All contributors have signed the CLA. Thank you for helping make BrowserOS better!
|
||||
|
||||
# Lock PR after merge to prevent signature tampering
|
||||
lock-pullrequest-aftermerge: true
|
||||
|
||||
# Custom commit messages
|
||||
create-file-commit-message: 'docs: Create CLA signatures file'
|
||||
signed-commit-message: 'docs: $contributorName signed the CLA in $owner/$repo#$pullRequestNo'
|
||||
All contributors have signed the CLA. Thank you!
|
||||
|
||||
42
.github/workflows/claude.yml
vendored
Normal file
42
.github/workflows/claude.yml
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
name: Claude Code
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, ready_for_review]
|
||||
issue_comment:
|
||||
types: [created]
|
||||
pull_request_review_comment:
|
||||
types: [created]
|
||||
issues:
|
||||
types: [opened, assigned]
|
||||
pull_request_review:
|
||||
types: [submitted]
|
||||
|
||||
jobs:
|
||||
claude:
|
||||
if: |
|
||||
github.event_name == 'pull_request' ||
|
||||
(github.event_name == 'issue_comment' && contains(github.event.comment.body, '@claude') && contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)) ||
|
||||
(github.event_name == 'pull_request_review_comment' && contains(github.event.comment.body, '@claude') && contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.comment.author_association)) ||
|
||||
(github.event_name == 'pull_request_review' && contains(github.event.review.body, '@claude') && contains(fromJSON('["OWNER","MEMBER","COLLABORATOR"]'), github.event.review.author_association)) ||
|
||||
(github.event_name == 'issues' && (contains(github.event.issue.body, '@claude') || contains(github.event.issue.title, '@claude')))
|
||||
runs-on: ubuntu-latest
|
||||
permissions:
|
||||
contents: write
|
||||
pull-requests: write
|
||||
issues: read
|
||||
id-token: write
|
||||
actions: read
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
fetch-depth: 1
|
||||
|
||||
- name: Run Claude Code
|
||||
id: claude
|
||||
uses: anthropics/claude-code-action@v1
|
||||
with:
|
||||
claude_code_oauth_token: ${{ secrets.CLAUDE_CODE_OAUTH_TOKEN }}
|
||||
additional_permissions: |
|
||||
actions: read
|
||||
57
.github/workflows/code-quality.yml
vendored
Normal file
57
.github/workflows/code-quality.yml
vendored
Normal file
@@ -0,0 +1,57 @@
|
||||
name: Code Quality
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
branches:
|
||||
- main
|
||||
paths:
|
||||
- 'packages/browseros-agent/**'
|
||||
|
||||
jobs:
|
||||
biome:
|
||||
name: runner / Biome
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: packages/browseros-agent
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup Biome
|
||||
uses: biomejs/setup-biome@v2
|
||||
with:
|
||||
version: latest
|
||||
|
||||
- name: Run Biome
|
||||
run: biome ci .
|
||||
|
||||
typecheck:
|
||||
name: runner / Typecheck
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: packages/browseros-agent
|
||||
permissions:
|
||||
contents: read
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun ci
|
||||
|
||||
- name: Run codegen
|
||||
run: bun run --cwd apps/agent codegen
|
||||
|
||||
- name: Run Typecheck
|
||||
run: bun run typecheck
|
||||
20
.github/workflows/pr-title.yml
vendored
Normal file
20
.github/workflows/pr-title.yml
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
name: PR Conventional Commit Validation
|
||||
|
||||
on:
|
||||
pull_request:
|
||||
types: [opened, synchronize, reopened, edited]
|
||||
|
||||
permissions:
|
||||
pull-requests: write
|
||||
issues: write
|
||||
contents: read
|
||||
|
||||
jobs:
|
||||
validate-pr-title:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: PR Conventional Commit Validation
|
||||
uses: ytanikin/pr-conventional-commits@1.5.1
|
||||
with:
|
||||
task_types: '["feat","fix","docs","test","ci","refactor","perf","chore","revert","build"]'
|
||||
custom_labels: '{"feat": "feature", "fix": "fix", "docs": "documentation", "test": "test", "ci": "CI/CD", "refactor": "refactor", "perf": "performance", "chore": "chore", "revert": "revert", "wip": "WIP"}'
|
||||
37
.github/workflows/release-agent-sdk.yml
vendored
Normal file
37
.github/workflows/release-agent-sdk.yml
vendored
Normal file
@@ -0,0 +1,37 @@
|
||||
name: Release Agent SDK
|
||||
|
||||
on:
|
||||
workflow_dispatch:
|
||||
|
||||
jobs:
|
||||
publish:
|
||||
if: github.ref == 'refs/heads/main'
|
||||
runs-on: ubuntu-latest
|
||||
defaults:
|
||||
run:
|
||||
working-directory: packages/browseros-agent/packages/agent-sdk
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v6
|
||||
|
||||
- uses: oven-sh/setup-bun@v2
|
||||
|
||||
- uses: actions/setup-node@v6
|
||||
with:
|
||||
node-version: "20"
|
||||
registry-url: "https://registry.npmjs.org"
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun ci
|
||||
working-directory: packages/browseros-agent
|
||||
|
||||
- name: Build
|
||||
run: bun run build
|
||||
|
||||
- name: Test
|
||||
run: bun test
|
||||
|
||||
- name: Publish
|
||||
run: npm publish --access public
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
|
||||
27
.github/workflows/test.yml
vendored
Normal file
27
.github/workflows/test.yml
vendored
Normal file
@@ -0,0 +1,27 @@
|
||||
name: Tests
|
||||
|
||||
on: []
|
||||
|
||||
jobs:
|
||||
test:
|
||||
name: Run Tests
|
||||
runs-on: macos-latest
|
||||
timeout-minutes: 10
|
||||
defaults:
|
||||
run:
|
||||
working-directory: packages/browseros-agent
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Setup Bun
|
||||
uses: oven-sh/setup-bun@v2
|
||||
|
||||
- name: Install dependencies
|
||||
run: bun ci
|
||||
|
||||
- name: Run all tests
|
||||
run: bun test:all
|
||||
env:
|
||||
PUPPETEER_EXECUTABLE_PATH: /Applications/Google Chrome.app/Contents/MacOS/Google Chrome
|
||||
Reference in New Issue
Block a user