fix(issues): allow local issues create/add_message without a Bear…
#1402
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
| name: CI test lanes | |
| on: | |
| pull_request: | |
| push: | |
| branches: | |
| - main | |
| - dev | |
| workflow_dispatch: | |
| permissions: | |
| contents: read | |
| concurrency: | |
| group: ci-test-lanes-${{ github.ref }} | |
| cancel-in-progress: true | |
| jobs: | |
| baseline: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "20" | |
| cache: "npm" | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Init inspector submodule (Vitest imports inspector sources) | |
| run: git submodule update --init --depth 1 inspector | |
| - name: Build @neotoma/client, @neotoma/agent, and cursor-hooks (Vitest hook tests) | |
| run: | | |
| npm ci --prefix packages/client | |
| npm run build --prefix packages/client | |
| npm ci --prefix packages/agent | |
| npm run build --prefix packages/agent | |
| npm ci --prefix packages/cursor-hooks | |
| npm run build --prefix packages/cursor-hooks | |
| # opencode-plugin imports @neotoma/client via "file:../client" — its | |
| # tests import src/ directly so no build step is needed, but the | |
| # node_modules symlink must exist for ESM resolution. | |
| npm ci --prefix packages/opencode-plugin | |
| - name: Type check | |
| run: npm run type-check | |
| - name: Lint | |
| run: npm run lint | |
| - name: Format check | |
| run: npm run format:check | |
| # Must run AFTER format:check so a stale committed file cannot be silently | |
| # re-formatted by `openapi:generate` (which runs prettier --write) before | |
| # the format gate sees it. Do not move this step above format:check. | |
| - name: OpenAPI types are in sync with openapi.yaml | |
| run: | | |
| npm run openapi:generate | |
| if ! git diff --quiet -- src/shared/openapi_types.ts; then | |
| echo "::error::src/shared/openapi_types.ts is out of sync with openapi.yaml. If you edited openapi.yaml, run 'npm run openapi:generate' and commit the regenerated src/shared/openapi_types.ts." | |
| git --no-pager diff -- src/shared/openapi_types.ts | head -100 | |
| exit 1 | |
| fi | |
| - name: Lint site copy | |
| run: npm run lint:site-copy | |
| - name: Build server (required by CLI tests) | |
| run: npm run build:server | |
| - name: Run unit Vitest suite (no DB) | |
| run: npm run test:unit | |
| - name: Validate Playwright coverage map | |
| run: npm run validate:coverage | |
| - name: Validate automated test catalog | |
| run: npm run validate:test-catalog | |
| - name: Fetch release tags (capability manifest is derived from vX.Y.Z tags) | |
| run: git fetch --tags --force | |
| - name: Validate capability manifest | |
| run: npm run validate:capability-manifest | |
| - name: Validate documentation dependencies | |
| run: npm run validate:doc-deps | |
| contract_parity: | |
| # Focused PR-time cross-surface contract-parity lane. | |
| # | |
| # Retrospective ent_68a9270e2e656da847c10ced: the `source_storage:'reference'` | |
| # feature shipped incomplete to an evaluator across three releases because the | |
| # covering integration tests ran only in the nightly remote_integration | |
| # workflow — never on the PR baseline lane, which runs `test:unit` (no DB). | |
| # | |
| # This lane runs ONLY the parity-critical store/reference integration tests | |
| # (MCP + REST surfaces driven through one shared scenario matrix) on every PR. | |
| # It deliberately does NOT pull the whole nightly integration suite onto each | |
| # PR — just the cross-surface parity gate — so it stays fast (~a few seconds | |
| # of tests). The tests run against the same local SQLite backend the nightly | |
| # job uses (default mode: RUN_REMOTE_TESTS unset), with file-parallelism | |
| # disabled to avoid SQLite lock contention between the two HTTP-server files. | |
| # | |
| # Implements task_policy cross_surface_contract_parity_tested_all_surfaces | |
| # (ent_2ad0677fe23c0c1878ae43e8) and | |
| # fixed_means_behavior_verified_not_contract_accepted (ent_db0b7855d47012084477fb00). | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "20" | |
| cache: "npm" | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Build server (integration tests boot the in-process Actions server) | |
| run: npm run build:server | |
| - name: Run cross-surface contract-parity integration tests | |
| run: npm run test:contract-parity | |
| frontend: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "20" | |
| cache: "npm" | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Run frontend Vitest suite | |
| run: npm run test:frontend | |
| site_export: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "20" | |
| cache: "npm" | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Validate route parity | |
| run: npm run validate:routes | |
| - name: Build UI | |
| run: npm run build:ui | |
| - name: Install Playwright browser (Chromium) | |
| run: npx playwright install --with-deps chromium | |
| - name: Validate locale parity | |
| run: npm run validate:locales | |
| - name: Build site export | |
| run: npm run build:site:pages | |
| - name: Validate site export | |
| run: npm run validate:site-export | |
| agentic_evals: | |
| # Tier 1 agentic-eval matrix. Runs all fixtures against the cursor-hooks | |
| # adapter using an in-process mock Neotoma server — no API key required. | |
| # Live-model cells (claude-code-plugin, codex-hooks, etc.) are Phase 1 | |
| # stubs and skip automatically. Add ANTHROPIC_API_KEY to repo secrets and | |
| # remove this comment when live harnesses graduate from stub status. | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "20" | |
| cache: "npm" | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Build @neotoma/client and cursor-hooks | |
| run: | | |
| npm ci --prefix packages/client | |
| npm run build --prefix packages/client | |
| npm ci --prefix packages/cursor-hooks | |
| npm run build --prefix packages/cursor-hooks | |
| - name: Run Tier 1 agentic evals | |
| run: npm run eval:tier1 | |
| eval_scenarios: | |
| # eval-harness SCENARIO lane (Tier 2). Runs the agent-driving scenarios in | |
| # packages/eval-harness/scenarios/ against a real in-process isolated | |
| # Neotoma server in REPLAY mode (committed cassettes — no API key required). | |
| # This is the CI gate for tool-behavior evals (agent calls correct / merge / | |
| # subscribe / …), which the hook-lifecycle agentic_evals lane cannot model. | |
| # Quarantined scenarios (meta.quarantine, tracked by neotoma#1726) are | |
| # skipped, not failed; cassette-less scenarios skip until recorded. | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "20" | |
| cache: "npm" | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Run eval-harness scenarios (replay) | |
| run: npm run eval:scenarios | |
| eval_combined: | |
| # COMBINED layered-matrix lane (WRIT state layer + Tier-2 agent layer). | |
| # Runs packages/eval-combined against a real isolated Neotoma server and | |
| # emits the per-category WRIT×Tier-2 coverage matrix — the qa-gate surface | |
| # for the QA-evals reframe (QE2): a regression in EITHER layer fails the | |
| # lane. Needs the writ submodule checked out + built; runs without an API | |
| # key (WRIT degrades to a substring judge; OPENAI_API_KEY/WRIT_JUDGE_API_KEY | |
| # gives higher-fidelity llm_judge scoring). The runner fails closed if a | |
| # requested WRIT run errors (neotoma#1738/#1739). | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout (with writ submodule) | |
| uses: actions/checkout@v4 | |
| # NOT submodules:recursive — other submodules (e.g. foundation) use SSH | |
| # URLs that fail in CI. writ is public HTTPS, so init ONLY it explicitly. | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "20" | |
| cache: "npm" | |
| - name: Init writ submodule (public HTTPS) | |
| run: git submodule update --init writ | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Build writ (eval-combined imports writ/dist) | |
| run: | | |
| npm ci --prefix writ | |
| npm run build --prefix writ | |
| - name: Run combined WRIT + Tier-2 matrix | |
| run: npm run eval:combined | |
| python_sdk: | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| - name: Setup Python | |
| uses: actions/setup-python@v5 | |
| with: | |
| python-version: "3.12" | |
| - name: Install neotoma-client with dev dependencies | |
| run: pip install -e "packages/client-python[dev]" | |
| - name: Run Python unit tests | |
| run: pytest packages/client-python/tests/ -v | |
| security_gates: | |
| # Gate G1–G3 + manifest sync (Track 1 of the pre-release security gates). | |
| # Always runs the manifest sync check + auth matrix; runs the static | |
| # rules + classifier output on every PR so reviewers see the | |
| # security-sensitive concerns before merge. | |
| # Source plan: .cursor/plans/pre-release_security_gates_44e01d74.plan.md | |
| # Threat model: docs/security/threat_model.md | |
| runs-on: ubuntu-latest | |
| steps: | |
| - name: Checkout | |
| uses: actions/checkout@v4 | |
| with: | |
| fetch-depth: 0 | |
| - name: Setup Node | |
| uses: actions/setup-node@v4 | |
| with: | |
| node-version: "20" | |
| cache: "npm" | |
| - name: Install dependencies | |
| run: npm ci | |
| - name: Classify diff (G1) | |
| run: | | |
| BASE_REF="" | |
| if [ "${{ github.event_name }}" = "pull_request" ]; then | |
| BASE_REF="origin/${{ github.event.pull_request.base.ref }}" | |
| else | |
| BASE_REF="origin/main" | |
| fi | |
| git fetch origin "${BASE_REF#origin/}" --depth=200 || true | |
| npm run security:classify-diff -- --base "$BASE_REF" --head HEAD --json > /tmp/security_classify_raw.txt 2>&1 | |
| # Strip npm script header lines before parsing JSON | |
| grep -v "^>" /tmp/security_classify_raw.txt | grep -v "^npm" > /tmp/security_classify.json || true | |
| cat /tmp/security_classify.json | |
| SENSITIVE=$(node -e "console.log(require('/tmp/security_classify.json').sensitive)") | |
| echo "SECURITY_SENSITIVE=$SENSITIVE" >> "$GITHUB_ENV" | |
| - name: Static rules (G2 — security:lint) | |
| run: npm run security:lint | |
| - name: Protected routes manifest sync (G3 + manifest-sync) | |
| run: npm run security:manifest:check | |
| - name: Topology auth matrix (G3) | |
| run: npm run test:security:auth-matrix | |
| - name: Surface sensitivity flag | |
| if: always() | |
| run: | | |
| echo "Security-sensitive diff: ${SECURITY_SENSITIVE:-unknown}" | |
| echo "Per docs/security/threat_model.md, sensitive PRs MUST land with a Security hardening supplement section and a same-release security_review.md." |