From bc40c698afa71d6cb72fba1a0e2f2ccb866a800c Mon Sep 17 00:00:00 2001 From: Robert DeRienzo Date: Tue, 3 Mar 2026 13:25:08 -0500 Subject: [PATCH 01/21] chore: add development branch workflow (#327) * chore: add development branch workflow - Add merge-gate.yml: enforces only 'development' can merge into main - Update CI/CodeQL/Docker workflows to run on both main and development - Update dependabot.yml: target-branch set to development for all ecosystems - Update copilot-instructions.md: document branch workflow convention - Rulesets configured: Main (requires merge-gate + squash-only), Development (requires CI status checks + PR) - Default branch set to development - All open PRs retargeted to development Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * fix: skip Vercel preview deployments on non-main branches Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * chore: trigger check refresh --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> --- .github/copilot-instructions.md | 1 + .github/dependabot.yml | 4 ++++ .github/workflows/ci.yml | 4 ++-- .github/workflows/codeql.yml | 4 ++-- .github/workflows/docker.yml | 2 +- .github/workflows/merge-gate.yml | 17 +++++++++++++++++ docs/vercel.json | 2 +- 7 files changed, 28 insertions(+), 6 deletions(-) create mode 100644 .github/workflows/merge-gate.yml diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md index a78fcd7..24f178c 100644 --- a/.github/copilot-instructions.md +++ b/.github/copilot-instructions.md @@ -14,4 +14,5 @@ Refer to [agents.md](../agents.md) at the repository root for full architecture, - Tests use `MockEmbeddingProvider` and in-memory SQLite (no sqlite-vec in tests). - Run `npm run typecheck && npm run test:coverage && npm run lint` before considering work complete. Use `test:coverage` (not `test`) — CI enforces coverage thresholds (statements ≥ 75%, branches ≥ 74%, functions ≥ 75%, lines ≥ 75%) and will reject PRs that drop below them. - Before creating a PR, use a `code-review` sub-agent to self-review your diff. Fix any issues it finds before opening the PR. +- **Branch workflow:** All feature branches and PRs target `development`. Only `development` can be merged into `main`. When creating branches, branch from `development`. When creating PRs, set the base to `development`. - **PR lifecycle is mandatory.** After pushing a PR, always: (1) wait for CI/CD to complete, (2) check if it passed, (3) fix failures and re-push if needed, (4) read and address all review comments, (5) verify CI is green again. A PR is not done until all checks pass and all review comments are resolved. See the "Pull Request Lifecycle" section in `agents.md` for the full workflow. diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 7f94626..4c13cec 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -2,6 +2,7 @@ version: 2 updates: - package-ecosystem: "npm" directory: "/" + target-branch: "development" schedule: interval: "weekly" groups: @@ -9,14 +10,17 @@ updates: update-types: ["minor", "patch"] - package-ecosystem: "pip" directory: "/sdk/python" + target-branch: "development" schedule: interval: "weekly" - package-ecosystem: "gomod" directory: "/sdk/go" + target-branch: "development" schedule: interval: "weekly" - package-ecosystem: "github-actions" directory: "/" + target-branch: "development" schedule: interval: "weekly" groups: diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 2058500..ffb7a93 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -2,9 +2,9 @@ name: CI on: push: - branches: [main] + branches: [main, development] pull_request: - branches: [main] + branches: [main, development] workflow_call: concurrency: diff --git a/.github/workflows/codeql.yml b/.github/workflows/codeql.yml index f1359a0..9e9be50 100644 --- a/.github/workflows/codeql.yml +++ b/.github/workflows/codeql.yml @@ -2,9 +2,9 @@ name: "CodeQL" on: push: - branches: [main] + branches: [main, development] pull_request: - branches: [main] + branches: [main, development] schedule: - cron: "0 6 * * 1" diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 02b50c4..39b632b 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -1,7 +1,7 @@ name: Docker on: push: - branches: [main] + branches: [main, development] tags: ["v*"] pull_request: paths: ["Dockerfile", "docker-compose.yml", ".dockerignore"] diff --git a/.github/workflows/merge-gate.yml b/.github/workflows/merge-gate.yml new file mode 100644 index 0000000..fc1de45 --- /dev/null +++ b/.github/workflows/merge-gate.yml @@ -0,0 +1,17 @@ +name: Merge Gate + +on: + pull_request: + branches: [main] + +jobs: + enforce-source-branch: + runs-on: ubuntu-latest + steps: + - name: Verify PR source is development branch + run: | + if [ "${{ github.head_ref }}" != "development" ]; then + echo "::error::Only the 'development' branch can be merged into main. This PR is from '${{ github.head_ref }}'." + exit 1 + fi + echo "✅ Source branch is 'development' — merge allowed." diff --git a/docs/vercel.json b/docs/vercel.json index 8758106..795d6ef 100644 --- a/docs/vercel.json +++ b/docs/vercel.json @@ -1,5 +1,5 @@ { - "ignoreCommand": "git diff --quiet HEAD^ HEAD -- .", + "ignoreCommand": "[ \"$VERCEL_GIT_COMMIT_REF\" != \"main\" ] || git diff --quiet HEAD^ HEAD -- .", "installCommand": "cd .. && npm install --include=dev --ignore-scripts", "buildCommand": "cd .. && npx vitepress build docs", "outputDirectory": ".vitepress/dist" From d0b21fa59f5e95a797423618239b64fd60d8fcc2 Mon Sep 17 00:00:00 2001 From: Robert DeRienzo Date: Tue, 3 Mar 2026 14:16:35 -0500 Subject: [PATCH 02/21] feat: create-pack from local folder or URL sources (#329) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * fix: comprehensive audit fixes — security, performance, resilience, API hardening Addresses findings from issue #314: - SSRF protection for webhook URLs (CRITICAL) - Scrub secrets from exports - Stored XSS prevention on document URL - O(n²) and N+1 fixes in bulk operations - Rate limit cache eviction improvement - SSE backpressure handling - Replace raw Error() with typed errors - Fetch timeouts on all network calls - Input validation on API parameters - Search query length limit - Silent catch block logging - DNS rebinding check fix - N+1 in Slack user resolution - Pagination on webhook/search list endpoints Closes #314 Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * Address PR review comments: fix SSE listener leak, preserve caller signals, add SSRF validation to webhook test, chunk SQL params, use dynamic import in test - SSE backpressure: create single disconnect promise, race against drain (no listener accumulation) - http-utils.ts/onenote.ts: use AbortSignal.any() to combine caller signal with timeout - Webhook test endpoint: validate URL with validateWebhookUrlSsrf before fetch - bulk.ts: chunk IN clause to 999 params max (SQLite limit) - webhooks.test.ts: dynamic import after vi.mock() for deterministic DNS mocking Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * ci: consolidate and fix CI/CD workflows - Merge lint + typecheck into single job (saves one npm ci) - Add concurrency groups to ci, docker, codeql (cancel stale runs) - Add dependency-review-action on PRs (block vulnerable deps) - Add workflow_call trigger to ci.yml for reusability - Remove duplicate npm publish from release.yml (release-please owns it) - Fix SDK paths: sdk-go/ → sdk/go/, sdk-python/ → sdk/python/ - Fix Dependabot paths to match actual SDK directories - Add github-actions ecosystem to Dependabot (keep actions up to date) Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> * feat: add HTML file parser for .html/.htm document indexing Adds HtmlParser using the existing node-html-markdown dependency. Strips

More

'; + const result = await parser.parse(Buffer.from(html)); + expect(result).toContain("Content"); + expect(result).toContain("More"); + expect(result).not.toContain("alert"); + expect(result).not.toContain("script"); + }); + + it("strips style tags", async () => { + const html = "

Visible

"; + const result = await parser.parse(Buffer.from(html)); + expect(result).toContain("Visible"); + expect(result).not.toContain("color"); + }); + + it("strips nav tags", async () => { + const html = + "

Article

"; + const result = await parser.parse(Buffer.from(html)); + expect(result).toContain("Article"); + expect(result).not.toContain("Home"); + }); + + it("handles full HTML documents with doctype and head", async () => { + const html = ` +Test Page +

Main Title

Body text here.

`; + const result = await parser.parse(Buffer.from(html)); + expect(result).toContain("Main Title"); + expect(result).toContain("Body text here"); + expect(result).not.toContain("color: blue"); + }); + + it("converts links to markdown format", async () => { + const html = 'Click here'; + const result = await parser.parse(Buffer.from(html)); + expect(result).toContain("[Click here]"); + expect(result).toContain("https://example.com"); + }); + + it("converts lists to markdown", async () => { + const html = ""; + const result = await parser.parse(Buffer.from(html)); + expect(result).toContain("One"); + expect(result).toContain("Two"); + expect(result).toContain("Three"); + }); + + it("handles empty HTML gracefully", async () => { + const result = await parser.parse(Buffer.from("")); + expect(result).toBe(""); + }); + + it("collapses excessive blank lines", async () => { + const html = "

First

Second

"; + const result = await parser.parse(Buffer.from(html)); + expect(result).not.toMatch(/\n{3,}/); + }); +}); From 0881d2b14b68ed3f9e0e52ddf95f5e7115bdb1c2 Mon Sep 17 00:00:00 2001 From: Robert DeRienzo Date: Tue, 3 Mar 2026 14:17:03 -0500 Subject: [PATCH 03/21] feat: add HTML file parser for .html/.htm document indexing (#318) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * feat: add HTML file parser for .html/.htm document indexing Adds HtmlParser using the existing node-html-markdown dependency. Strips