* ci(security): run deterministic eval tests in affected-area CI (Task 04) The build-check job validated build + suite structure but never ran the tests, and its summary referenced a `test:ci` script that did not exist. Make affected-area CI meaningful: - Add `test:ci` to evals/framework running the offline, deterministic Vitest allowlist (7 files / 112 tests) — no model, network, or paid execution. - Add a required "Run deterministic tests" step to build-check; a failure fails the job and the existing PR summary gate (which keys on build-check.result) fails closed. - Correct the summary note to state test:ci runs the deterministic allowlist and that model/network agent suites are excluded on PRs. The broader deterministic suite has 3 pre-existing failing files (framework-confidence, logger, test-runner; confirmed failing before this work) which are intentionally out of the allowlist and tracked separately. Validated locally: build, validate:suites:all, and test:ci all exit 0. * ci(security): least privilege permissions + pin actions to SHAs (Task 05) Harden all 9 GitHub Actions workflows: Least privilege: - Add explicit top-level `permissions: contents: read` to installer-checks, validate-test-suites, and opencode (opencode's job keeps the writes it needs; the top level now defaults to read). - Every workflow now declares an explicit top-level permissions block. - Write scopes retained only where justified (releases, doc/registry commits, follow-up PRs, and sync-docs' issues.create). Immutable action pinning: - Pin every `uses:` to a full 40-char commit SHA with a version comment, including first-party actions/* (checkout, github-script, setup-node, upload-artifact) and third-party (oven-sh/setup-bun). - Replace the two mutable refs that could change under us at any push: ludeeus/action-shellcheck@master and sst/opencode/github@latest. Record all SHAs, versions, and permission justifications in docs/maintenance/repository-recovery/action-pin-inventory.md. Verified: all 9 workflows parse as valid YAML; no floating tag/branch refs remain; every workflow has a top-level permissions block. * docs(security): add SECURITY.md and private-reporting checklist (Task 06) - Add root SECURITY.md: supported versions (0.7.x), private reporting via GitHub's "Report a vulnerability", best-effort response expectations, coordinated disclosure, and no-secret guidance. - Add private-vulnerability-reporting checklist that separates repository file work (this PR) from GitHub settings changes that require their own approval (Task 07: enabling private vulnerability reporting). No external links to validate; the reporting path uses the repo Security tab. SECURITY.md documents the private reporting path ahead of Task 07 enabling it. * ci(security): add dependency governance and ownership controls (Task 08) - .github/dependabot.yml: weekly grouped github-actions updates (keeps the Task 05 SHA pins current). Scoped to actions only — the primary lockfile is bun.lock and Dependabot's npm ecosystem would desync it; npm dependency risk is covered by dependency-review below. - .github/workflows/dependency-review.yml: runs on PRs with contents: read, SHA-pinned actions, fail-on-severity: high to block newly introduced high-severity vulnerabilities (exceptions documented inline). - .github/CODEOWNERS: default owner @darrenhinde with explicit ownership of security-sensitive paths (workflows, dependabot, CODEOWNERS, SECURITY.md, scripts/validation). Verified: dependabot.yml and dependency-review.yml are valid YAML; dependency-review actions are SHA-pinned with contents: read; CODEOWNERS owner is the repository owner. * docs(security): record GitHub security settings evidence (Task 07) Enable private vulnerability reporting and record read-back evidence. Settings changed (each approved immediately before, verified by read-back): - Private vulnerability reporting: enabled=false -> enabled=true. The Security tab now offers "Report a vulnerability", making the path documented in SECURITY.md live. - Dependency Graph / Dependabot alerts: 404 -> 204. This was an undocumented prerequisite of Task 08's dependency-review.yml, which failed with "Dependency graph is not enabled"; the Dependency Review check on PR #336 went fail -> pass after enabling it. No other repository setting was modified; secret scanning and push protection are unchanged, and dependabot_security_updates remains disabled (out of scope, would need its own approval). Both changes are reversible via the corresponding DELETE calls. Marks Part B of the private-vulnerability-reporting checklist complete.
226 lines
8.6 KiB
YAML
226 lines
8.6 KiB
YAML
name: Sync Documentation
|
|
|
|
on:
|
|
push:
|
|
branches:
|
|
- main
|
|
paths:
|
|
- 'registry.json'
|
|
- '.opencode/agent/**'
|
|
- '.opencode/command/**'
|
|
- '.opencode/context/**'
|
|
workflow_dispatch:
|
|
inputs:
|
|
force_update:
|
|
description: 'Force documentation update even if no changes detected'
|
|
required: false
|
|
type: boolean
|
|
default: false
|
|
|
|
permissions:
|
|
contents: write
|
|
pull-requests: write
|
|
issues: write
|
|
|
|
jobs:
|
|
check-sync-needed:
|
|
name: Check if Docs Need Sync
|
|
runs-on: ubuntu-latest
|
|
outputs:
|
|
needs_sync: ${{ steps.check.outputs.needs_sync }}
|
|
changes_detected: ${{ steps.check.outputs.changes_detected }}
|
|
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
with:
|
|
fetch-depth: 2
|
|
|
|
- name: Install dependencies
|
|
run: |
|
|
sudo apt-get update
|
|
sudo apt-get install -y jq
|
|
|
|
- name: Check if sync needed
|
|
id: check
|
|
run: |
|
|
# Skip if this is an automated commit to prevent loops
|
|
COMMIT_MSG=$(git log -1 --pretty=%B)
|
|
if echo "$COMMIT_MSG" | grep -qE "\[skip ci\]|\[skip-docs\]|auto-update registry|bump version|Sync documentation"; then
|
|
echo "needs_sync=false" >> $GITHUB_OUTPUT
|
|
echo "changes_detected=Automated commit - skipping to prevent loops" >> $GITHUB_OUTPUT
|
|
exit 0
|
|
fi
|
|
|
|
# Force update if requested
|
|
if [ "${{ github.event.inputs.force_update }}" = "true" ]; then
|
|
echo "needs_sync=true" >> $GITHUB_OUTPUT
|
|
echo "changes_detected=Force update requested" >> $GITHUB_OUTPUT
|
|
exit 0
|
|
fi
|
|
|
|
# Check if registry.json changed
|
|
if git diff HEAD^ HEAD --name-only | grep -q "registry.json"; then
|
|
echo "needs_sync=true" >> $GITHUB_OUTPUT
|
|
echo "changes_detected=Registry updated" >> $GITHUB_OUTPUT
|
|
exit 0
|
|
fi
|
|
|
|
# Check if component files changed
|
|
if git diff HEAD^ HEAD --name-only | grep -qE "^\.opencode/(agent|command|context)/"; then
|
|
echo "needs_sync=true" >> $GITHUB_OUTPUT
|
|
echo "changes_detected=Component files updated" >> $GITHUB_OUTPUT
|
|
exit 0
|
|
fi
|
|
|
|
echo "needs_sync=false" >> $GITHUB_OUTPUT
|
|
echo "changes_detected=No relevant changes" >> $GITHUB_OUTPUT
|
|
|
|
sync-documentation:
|
|
name: Sync Documentation with OpenCode
|
|
runs-on: ubuntu-latest
|
|
needs: check-sync-needed
|
|
if: needs.check-sync-needed.outputs.needs_sync == 'true'
|
|
outputs:
|
|
branch_name: ${{ steps.create_branch.outputs.branch_name }}
|
|
issue_number: ${{ steps.create_issue.outputs.result }}
|
|
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
with:
|
|
fetch-depth: 0
|
|
|
|
- name: Create sync branch
|
|
id: create_branch
|
|
run: |
|
|
BRANCH_NAME="docs/auto-sync-$(date +%Y%m%d-%H%M%S)"
|
|
echo "branch_name=$BRANCH_NAME" >> $GITHUB_OUTPUT
|
|
|
|
git config user.name "github-actions[bot]"
|
|
git config user.email "github-actions[bot]@users.noreply.github.com"
|
|
|
|
git checkout -b "$BRANCH_NAME"
|
|
git push -u origin "$BRANCH_NAME"
|
|
|
|
- name: Create sync issue for OpenCode
|
|
id: create_issue
|
|
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
|
|
with:
|
|
script: |
|
|
const issue = await github.rest.issues.create({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
title: '🤖 Auto-sync documentation with registry',
|
|
body: `## Documentation Sync Request
|
|
|
|
**Trigger:** ${{ needs.check-sync-needed.outputs.changes_detected }}
|
|
**Branch:** \`${{ steps.create_branch.outputs.branch_name }}\`
|
|
**Commit:** ${{ github.sha }}
|
|
|
|
### Task
|
|
|
|
Please review the current \`registry.json\` and update the following documentation files to ensure they accurately reflect the current component counts and descriptions:
|
|
|
|
1. **README.md** - Update installation profile component counts:
|
|
- Essential profile: Update component count
|
|
- Developer profile: Update component count
|
|
- Business profile: Update component count
|
|
- Full profile: Update component count
|
|
- Advanced profile: Update component count
|
|
|
|
2. **README.md** - Verify "What's Included" section lists match registry
|
|
|
|
3. **docs/README.md** - Ensure component references are accurate
|
|
|
|
### Instructions
|
|
|
|
1. Read \`registry.json\` to get current component counts
|
|
2. Extract profile component counts from \`.profiles.<profile>.components | length\`
|
|
3. Update README.md sections that reference component counts
|
|
4. Ensure consistency across all documentation
|
|
5. Commit changes with message: "docs: sync component counts with registry [skip-docs]"
|
|
|
|
**IMPORTANT:** Include \`[skip-docs]\` in commit message to prevent workflow loops!
|
|
|
|
### Context Files to Load
|
|
|
|
- \`registry.json\` - Source of truth for components
|
|
- \`README.md\` - Main documentation file
|
|
- \`docs/README.md\` - Documentation index
|
|
|
|
### Validation
|
|
|
|
After updates, verify:
|
|
- All component counts match registry
|
|
- No broken links
|
|
- Consistent formatting
|
|
- No duplicate information
|
|
|
|
/opencode
|
|
|
|
---
|
|
|
|
**Note:** This is an automated documentation sync. Review changes carefully before merging.`,
|
|
labels: ['documentation', 'automated']
|
|
});
|
|
|
|
return issue.data.number;
|
|
|
|
- name: Wait for OpenCode to process
|
|
run: |
|
|
echo "OpenCode will process the issue and make changes to branch: ${{ steps.create_branch.outputs.branch_name }}"
|
|
echo "Issue created: #${{ steps.create_issue.outputs.result }}"
|
|
echo ""
|
|
echo "The workflow will:"
|
|
echo "1. OpenCode reads the issue"
|
|
echo "2. Analyzes registry.json"
|
|
echo "3. Updates documentation files"
|
|
echo "4. Commits changes to the branch"
|
|
echo "5. Another workflow will create a PR after OpenCode finishes"
|
|
echo ""
|
|
echo "Check the issue for progress: https://github.com/${{ github.repository }}/issues/${{ steps.create_issue.outputs.result }}"
|
|
echo ""
|
|
echo "⏳ Note: OpenCode may take several minutes to complete the task."
|
|
echo "The PR will be created automatically once OpenCode commits changes."
|
|
|
|
# This job is intentionally removed - PR creation should be manual or triggered by a separate event
|
|
# after OpenCode completes its work, not on a timer
|
|
|
|
cleanup-on-failure:
|
|
name: Cleanup on Failure
|
|
runs-on: ubuntu-latest
|
|
needs: [check-sync-needed, sync-documentation]
|
|
if: failure()
|
|
|
|
steps:
|
|
- name: Checkout repository
|
|
uses: actions/checkout@34e114876b0b11c390a56381ad16ebd13914f8d5 # v4
|
|
|
|
- name: Delete branch if created
|
|
run: |
|
|
BRANCH_NAME="${{ needs.sync-documentation.outputs.branch_name }}"
|
|
if [ -n "$BRANCH_NAME" ]; then
|
|
git push origin --delete "$BRANCH_NAME" || true
|
|
echo "Cleaned up branch: $BRANCH_NAME"
|
|
fi
|
|
|
|
- name: Comment on issue
|
|
if: needs.sync-documentation.outputs.issue_number
|
|
uses: actions/github-script@f28e40c7f34bde8b3046d885e986cb6290c5673b # v7
|
|
with:
|
|
script: |
|
|
await github.rest.issues.createComment({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: ${{ needs.sync-documentation.outputs.issue_number }},
|
|
body: '❌ Documentation sync workflow failed. Please check the workflow logs and sync manually if needed.'
|
|
});
|
|
|
|
await github.rest.issues.update({
|
|
owner: context.repo.owner,
|
|
repo: context.repo.repo,
|
|
issue_number: ${{ needs.sync-documentation.outputs.issue_number }},
|
|
state: 'closed',
|
|
labels: ['documentation', 'automated', 'failed']
|
|
});
|