Skip to content

feat(security): add CI, CodeQL, dependency review, and PR security checklist - #1

Merged
intellegix merged 2 commits into
masterfrom
feature/security-guardrails
Feb 23, 2026
Merged

feat(security): add CI, CodeQL, dependency review, and PR security checklist#1
intellegix merged 2 commits into
masterfrom
feature/security-guardrails

Conversation

@intellegix

Copy link
Copy Markdown
Owner

Summary

  • CI pipeline: pytest matrix (Python 3.11, 3.12) on push/PR to master, all Actions SHA-pinned
  • CodeQL: static analysis on push/PR + weekly Monday schedule
  • Dependency review: blocks PRs introducing high-severity vulns, denies AGPL/GPL-3.0 licenses
  • OpenSSF Scorecard: continuous security posture monitoring with SARIF upload
  • Dependabot: weekly updates for pip and github-actions ecosystems (5 PR limit each)
  • PR template: security review checklist for maintainer review
  • SECURITY.md: vulnerability reporting policy (email, 72h response)
  • CONTRIBUTING.md: contribution guidelines (issue first, no new deps without discussion)

All GitHub Actions are pinned to full commit SHA to prevent supply chain attacks via tag mutation.

Test plan

  • Verify CI workflow runs and passes on this PR
  • Verify CodeQL analysis appears in Security tab
  • Verify dependency review check appears on PR
  • Verify PR template auto-populates on new PRs
  • Configure branch protection on master (Phase 1 — manual GitHub UI)
  • Add CI job names as required status checks after merge

🤖 Generated with Claude Code

…klist

- CI pipeline: pytest matrix (Python 3.11, 3.12) on push/PR to master
- CodeQL: static analysis on push/PR + weekly schedule
- Dependency review: blocks PRs with high-severity vulns, denies AGPL/GPL-3.0
- OpenSSF Scorecard: continuous security posture monitoring with SARIF upload
- Dependabot: weekly updates for pip and github-actions ecosystems
- PR template: security review checklist for maintainer
- SECURITY.md: vulnerability reporting policy
- CONTRIBUTING.md: contribution guidelines
- All GitHub Actions pinned to full commit SHA (not tags)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@github-advanced-security

Copy link
Copy Markdown

This pull request sets up GitHub code scanning for this repository. Once the scans have completed and the checks have passed, the analysis results for this pull request branch will appear on this overview. Once you merge this pull request, the 'Security' tab will show more code scanning analysis results (for example, for the default branch). Depending on your configuration and choice of analysis tool, future pull requests will be annotated with code scanning analysis results. For more information about GitHub code scanning, check out the documentation.

…s modes

DOM signals (sources, action buttons) appear mid-generation on Perplexity,
causing research_query to scrape partial responses. Added three guards:
- Min elapsed time before trusting DOM signals (45s research, 90s labs)
- Min text length requirement (1500 chars)
- 10s confirmation wait after DOM triggers to verify text stopped growing

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@intellegix
intellegix merged commit b3c0732 into master Feb 23, 2026
4 of 5 checks passed
intellegix pushed a commit that referenced this pull request May 14, 2026
Two Claude Code sessions running /research-perplexity simultaneously
produced the user-visible symptom "browsers kept canceling each other
and trying." Forensic evidence on 2026-05-14 07:57 PDT: Session 2
spawned three Chrome temp profiles in sequence (council_np_nfeloa8y_
at +0s, wautgz7l_ at +4s = retry #1, 2ctuv7v_ at +58s = retry #2)
for what should have been ONE logical query. Both sessions eventually
returned valid synthesis (error: null), but the retry cascade is the
symptom.

Root cause (per /research-perplexity diagnosis, 129s deep query +
97s plan critique): the 4-second failure window is too fast for
Cloudflare/rate-limit/WebSocket; matches Windows OS focus-acquisition
timing. Session 2's chromium.launch_persistent_context (channel=
"chrome", headless=False) calls SetForegroundWindow / BringWindow-
ToTop during startup, stealing OS-level keyboard focus from
Session 1's page.keyboard.type("/research") + press("Space") mid-
keystroke. Wrong target receives keys; slash-command palette
dismissed before commit; query submits in Search mode instead of
Research; .prose comes back empty; server.js retry-once spawns new
subprocess → new Chrome window.

The amplifier: _verify_research_activation (and council/labs siblings)
returned optimistic True even when the indicator couldn't be found,
so the focus glitch turned into a silent bad-submission instead of a
clean abort.

Changes:

1. New file submission_lock.py — cross-process FileLock around the
   focus-sensitive submit critical section. Co-located with
   SessionSemaphore (~/.claude/config/browser-sessions/.perplexity_-
   submit.lock). Timeout scales with MAX_CONCURRENT_SESSIONS
   (max(120, MAX*30) → 240s at saturation, prevents tail starvation).
   180s stale-mtime reclaim covers SIGKILL'd holders.

2. council_browser.py: PerplexityCouncil._acquire_submit_lock async
   helper wraps FileLock.acquire in asyncio.to_thread to avoid
   blocking the event loop. The submit critical section in run()
   (activate_mode + submit_query) is wrapped in try/finally with
   the lock acquired BEFORE activate_mode (the very first input
   click inside activate_mode is itself focus-sensitive and must be
   inside the lock). Released after submit_query returns (which
   already internally waits for .prose to appear, proving the
   submission landed). wait_for_completion runs OUTSIDE the lock —
   fully parallel across sessions.

3. council_browser.py: _verify_research_activation, _verify_council_-
   activation, _verify_labs_activation rewritten as 2-tier selector
   cascades. Tier 1: exact-text match on the activated mode pill.
   Tier 2: looser case-insensitive contains-scan tolerating
   Perplexity DOM tweaks. Both miss → SELECTOR_DRIFT_DETECTED at
   log level, return False (was: optimistic True). Caller in run()
   short-circuits cleanly on False with the existing artifact-save +
   error-return path. Step 6 plan critique ruled this hygiene on a
   shared bug class, not scope creep.

Verification:
- ast.parse council_browser.py + submission_lock.py clean
- get_submit_lock() returns WindowsFileLock, timeout=240s,
  path=~/.claude/config/browser-sessions/.perplexity_submit.lock
- council_browser imports clean; PerplexityCouncil._acquire_submit_lock
  attribute present; get_submit_lock symbol imported
- test_parallel.py default suite 7/7 PASS (no regressions to existing
  SessionSemaphore + browser-launch tests)
- LIVE concurrent-Claude verification deferred to next user-triggered
  two-session research_query — expected: 2 Chrome windows ~4s apart,
  no retry subprocess spawn, exactly 2 council_np_* temp dirs

Plan: ~/.claude/plans/lexical-toasting-babbage.md (Step 6 APPROVED-WITH-
CONDITIONS, all 5 conditions integrated).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants