chore: release v1.0.10 - security/deploy fixes merged, deploy green #76
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| # ============================================================================= | |
| # CI/CD Workflow: OpenSIN Documentation Build & Deploy | |
| # ============================================================================= | |
| # This workflow builds the VitePress documentation site using bun (not npm!) | |
| # and deploys to Cloudflare Pages on the main branch. | |
| # | |
| # BUN-ONLY MANDATE (AGENTS.md): npm is permanently banned. | |
| # Global Brain hooks (PRIORITY -100.0) sync before/after every run. | |
| # | |
| # Secrets required (set in GitHub repo settings): | |
| # - CLOUDFLARE_API_TOKEN: Cloudflare Pages API token | |
| # - CLOUDFLARE_ACCOUNT_ID: Cloudflare account ID | |
| # ============================================================================= | |
| name: Docs Build & Deploy | |
| on: | |
| push: | |
| branches: [main, fix/docs-modernize-standards] | |
| paths-ignore: | |
| - 'worktrees/**' | |
| - '.worktrees/**' | |
| - '*.wt/**' | |
| pull_request: | |
| branches: [main] | |
| paths-ignore: | |
| - 'worktrees/**' | |
| - '.worktrees/**' | |
| - '*.wt/**' | |
| # ============================================================================= | |
| # Environment variables — Bun version pinned for reproducibility | |
| # ============================================================================= | |
| env: | |
| BUN_VERSION: "1.3.12" | |
| NODE_VERSION: "22" | |
| # ============================================================================= | |
| # Job definitions | |
| # ============================================================================= | |
| jobs: | |
| # --------------------------------------------------------------------------- | |
| # Job: build | |
| # Purpose: Install dependencies with bun, run VitePress build, verify output | |
| # --------------------------------------------------------------------------- | |
| build: | |
| name: VitePress Build (bun) | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 15 | |
| steps: | |
| # ----------------------------------------------------------------------- | |
| # STEP 1: Global Brain sync BEFORE run (PRIORITY -100.0 mandate) | |
| # Loads active context from the persistent brain before each OpenCode run | |
| # ----------------------------------------------------------------------- | |
| - name: Global Brain sync before run | |
| run: | | |
| echo "=== PCPM Before-Run Hook ===" | |
| BRAIN_CLI="/Users/jeremy/dev/global-brain/src/cli.js" | |
| if [ -f "$BRAIN_CLI" ]; then | |
| node "$BRAIN_CLI" orchestrate \ | |
| --project opensin-docs \ | |
| --project-root "$PWD" \ | |
| 2>/dev/null || true | |
| echo "Global Brain sync completed" | |
| else | |
| echo "Global Brain sync skipped on non-local runner" | |
| fi | |
| # ----------------------------------------------------------------------- | |
| # STEP 2: Checkout with full history for proper submodule handling | |
| # ----------------------------------------------------------------------- | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| submodules: true | |
| fetch-depth: 0 | |
| # ----------------------------------------------------------------------- | |
| # STEP 3: Install Bun (required — npm permanently banned per AGENTS.md) | |
| # ----------------------------------------------------------------------- | |
| - name: Install Bun | |
| uses: oven-sh/setup-bun@v2 | |
| with: | |
| bun-version: "${{ env.BUN_VERSION }}" | |
| # ----------------------------------------------------------------------- | |
| # STEP 4: Install dependencies ONLY using bun (AGENTS.md CI/CD mandate) | |
| # Bun is ~90% faster and uses 10x less RAM than npm | |
| # ----------------------------------------------------------------------- | |
| - name: Install dependencies (bun ONLY — npm banned per AGENTS.md) | |
| run: bun install | |
| # ----------------------------------------------------------------------- | |
| # STEP 5: Lint check — verify NO npm patterns in source code | |
| # This ensures the BUN-ONLY mandate is enforced across all source files | |
| # ----------------------------------------------------------------------- | |
| - name: Lint check (no npm patterns) | |
| run: | | |
| echo "=== BUN-ONLY Verification ===" | |
| NPM_PATTERNS=$(grep -RInE "npm install|npm run|package-lock|npx |bunx " . \ | |
| --include="*.md" \ | |
| --include="*.json" \ | |
| --include="*.yml" \ | |
| --include="*.yaml" \ | |
| --include="*.sh" \ | |
| --exclude-dir=node_modules \ | |
| --exclude-dir=.git \ | |
| --exclude-dir=worktrees \ | |
| --exclude-dir=.worktrees \ | |
| --exclude-dir='*.wt' \ | |
| --exclude-dir=.vitepress \ | |
| --exclude-dir=.github \ | |
| --exclude=AGENTS.md \ | |
| 2>/dev/null | grep -v "node_modules" || true) | |
| if [ -n "$NPM_PATTERNS" ]; then | |
| echo "FAIL: Found npm patterns:" | |
| echo "$NPM_PATTERNS" | |
| exit 1 | |
| else | |
| echo "PASS: No npm patterns found — BUN-ONLY verified" | |
| fi | |
| # ----------------------------------------------------------------------- | |
| # STEP 6: Build VitePress documentation site | |
| # ----------------------------------------------------------------------- | |
| - name: Build docs | |
| run: | | |
| echo "=== VitePress Build ===" | |
| bun ./scripts/build-docs.mjs | |
| # ----------------------------------------------------------------------- | |
| # STEP 7: Verify build output exists | |
| # VitePress outputs to .vitepress/dist/ — this must exist for deploy | |
| # ----------------------------------------------------------------------- | |
| - name: Verify build output exists | |
| run: | | |
| echo "=== Build Verification ===" | |
| if [ -d "docs/.vitepress/dist" ] && [ -f "docs/.vitepress/dist/index.html" ]; then | |
| echo "PASS: Build output verified" | |
| echo " Dist size: $(du -sh docs/.vitepress/dist | cut -f1)" | |
| echo " Files: $(find docs/.vitepress/dist -type f | wc -l)" | |
| else | |
| echo "FAIL: Build output missing or incomplete" | |
| echo " docs/.vitepress/dist exists: $(test -d docs/.vitepress/dist && echo YES || echo NO)" | |
| ls -la docs/.vitepress/ 2>/dev/null || echo "No docs/.vitepress dir" | |
| exit 1 | |
| fi | |
| # ----------------------------------------------------------------------- | |
| # STEP 8: Global Brain sync AFTER successful build (PRIORITY -100.0) | |
| # Extracts knowledge from the completed session back into the brain | |
| # ----------------------------------------------------------------------- | |
| - name: Global Brain sync after run | |
| if: success() | |
| run: | | |
| echo "=== PCPM After-Run Hook ===" | |
| BRAIN_CLI="/Users/jeremy/dev/global-brain/src/cli.js" | |
| if [ -f "$BRAIN_CLI" ]; then | |
| node "$BRAIN_CLI" extract-knowledge \ | |
| --project opensin-docs \ | |
| --project-root "$PWD" \ | |
| 2>/dev/null || true | |
| echo "Post-run knowledge extraction completed" | |
| else | |
| echo "Post-run knowledge extraction skipped on non-local runner" | |
| fi | |
| # ----------------------------------------------------------------------- | |
| # STEP 9: Upload build artifacts for deploy job | |
| # Artifacts are needed because build and deploy are separate jobs | |
| # ----------------------------------------------------------------------- | |
| - name: Upload build artifacts | |
| if: github.ref == 'refs/heads/main' | |
| uses: actions/upload-pages-artifact@v3 | |
| with: | |
| path: docs/.vitepress/dist | |
| # --------------------------------------------------------------------------- | |
| # Job: deploy | |
| # Purpose: Deploy built docs to Cloudflare Pages (main branch only) | |
| # --------------------------------------------------------------------------- | |
| deploy: | |
| name: Cloudflare Pages Deploy | |
| if: github.ref == 'refs/heads/main' | |
| needs: build | |
| runs-on: ubuntu-latest | |
| timeout-minutes: 10 | |
| environment: | |
| name: production | |
| url: https://docs.opensin.ai | |
| permissions: | |
| contents: read | |
| deployments: write | |
| steps: | |
| # ----------------------------------------------------------------------- | |
| # STEP 1: Download build artifacts from the build job | |
| # ----------------------------------------------------------------------- | |
| - name: Download built artifacts | |
| uses: actions/download-artifact@v4 | |
| with: | |
| name: github-pages | |
| path: docs/.vitepress/dist | |
| # ----------------------------------------------------------------------- | |
| # STEP 2: Validate required Cloudflare secrets exist | |
| # Fail fast with explicit diagnostics instead of surfacing a vague deploy error. | |
| # ----------------------------------------------------------------------- | |
| - name: Validate Cloudflare secrets | |
| run: | | |
| if [ -z "${{ secrets.CLOUDFLARE_API_TOKEN }}" ]; then | |
| echo "::error::CLOUDFLARE_API_TOKEN is missing or empty in repository secrets." | |
| exit 1 | |
| fi | |
| if [ -z "${{ secrets.CLOUDFLARE_ACCOUNT_ID }}" ]; then | |
| echo "::error::CLOUDFLARE_ACCOUNT_ID is missing or empty in repository secrets." | |
| exit 1 | |
| fi | |
| echo "PASS: Cloudflare secrets are present" | |
| # ----------------------------------------------------------------------- | |
| # STEP 3: Verify Cloudflare authentication and Pages access BEFORE deploy | |
| # 403 here means invalid token, wrong account id, or insufficient Pages scope. | |
| # ----------------------------------------------------------------------- | |
| - name: Test Cloudflare authentication and permissions | |
| run: | | |
| HTTP_CODE=$(curl -sS -o /tmp/cf_pages_projects.json -w "%{http_code}" \ | |
| -X GET "https://api.cloudflare.com/client/v4/accounts/${{ secrets.CLOUDFLARE_ACCOUNT_ID }}/pages/projects" \ | |
| -H "Authorization: Bearer ${{ secrets.CLOUDFLARE_API_TOKEN }}") | |
| if [ "$HTTP_CODE" -ne 200 ]; then | |
| echo "::error::Cloudflare API returned HTTP $HTTP_CODE while listing Pages projects." | |
| echo "::error::403 indicates an invalid/expired token, wrong account id, or missing Pages permissions." | |
| echo "::error::Required minimum scopes: Account Settings: Read and Pages: Edit on the target account." | |
| cat /tmp/cf_pages_projects.json | |
| exit 1 | |
| fi | |
| if ! grep -q '"name":"opensin-docs"' /tmp/cf_pages_projects.json; then | |
| echo "::warning::Cloudflare auth succeeded, but the 'opensin-docs' Pages project was not found in the account listing." | |
| echo "::warning::Verify CLOUDFLARE_ACCOUNT_ID points to the account that owns the Pages project." | |
| else | |
| echo "PASS: Cloudflare authentication and Pages project access verified" | |
| fi | |
| # ----------------------------------------------------------------------- | |
| # STEP 4: Deploy to Cloudflare Pages | |
| # Uses Cloudflare Pages action for deployment (direct artifact upload, not npm) | |
| # ----------------------------------------------------------------------- | |
| - name: Deploy to Cloudflare Pages | |
| uses: cloudflare/pages-action@v1 | |
| with: | |
| apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }} | |
| accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }} | |
| projectName: opensin-docs | |
| directory: docs/.vitepress/dist | |
| gitHubToken: ${{ secrets.GITHUB_TOKEN }} | |
| branch: main |