diff --git a/.github/scripts/pr-conflict-notifier.js b/.github/scripts/pr-conflict-notifier.cjs similarity index 100% rename from .github/scripts/pr-conflict-notifier.js rename to .github/scripts/pr-conflict-notifier.cjs diff --git a/.github/scripts/pr-malware-scan.js b/.github/scripts/pr-malware-scan.cjs similarity index 99% rename from .github/scripts/pr-malware-scan.js rename to .github/scripts/pr-malware-scan.cjs index 86b31736..192ac07f 100644 --- a/.github/scripts/pr-malware-scan.js +++ b/.github/scripts/pr-malware-scan.cjs @@ -37,7 +37,7 @@ const MEDIA_EXT = /\.(woff2?|ttf|otf|eot|png|jpe?g|gif|ico|webp|bmp|pdf|mp3|mp4| const DOC_EXT = /\.(md|mdx|txt)$/i; const GENERATED = /(^|\/)(package-lock\.json|Cargo\.lock|yarn\.lock|pnpm-lock\.yaml)$|(^|\/)test_snapshots\/|(^|\/)generated\/|\.snap$|\.min\.(js|css)$|\.svg$/; const JS_LIKE = /\brequire\s*\(|\bimport\s+[\w{*]|=>|\bfunction\s*\(|\beval\s*\(|\bprocess\.(env|argv)|module\.exports|child_process/; -const SELF = '.github/scripts/pr-malware-scan.js'; +const SELF = '.github/scripts/pr-malware-scan.cjs'; // Code patterns checked on every added line. Docs only get WARN for these, // since READMEs legitimately show install one-liners. diff --git a/.github/workflows/pr-conflict-notifier.yml b/.github/workflows/pr-conflict-notifier.yml index bd338715..c4d9cdce 100644 --- a/.github/workflows/pr-conflict-notifier.yml +++ b/.github/workflows/pr-conflict-notifier.yml @@ -42,5 +42,5 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | - const notify = require('./.github/scripts/pr-conflict-notifier.js'); + const notify = require('./.github/scripts/pr-conflict-notifier.cjs'); await notify({ github, context, core, dryRun: context.eventName === 'workflow_dispatch' && `${{ inputs.dry_run }}` === 'true' }); diff --git a/.github/workflows/pr-malware-scan.yml b/.github/workflows/pr-malware-scan.yml index 663d98bf..bc567b18 100644 --- a/.github/workflows/pr-malware-scan.yml +++ b/.github/workflows/pr-malware-scan.yml @@ -1,7 +1,7 @@ name: PR malware scan # Scans every PR for malware and supply-chain tricks (see -# .github/scripts/pr-malware-scan.js). High-severity findings fail this check, +# .github/scripts/pr-malware-scan.cjs). High-severity findings fail this check, # label the PR `security-review` and @mention the author. # # Why pull_request_target: it is the only trigger that runs on fork PRs @@ -40,5 +40,5 @@ jobs: uses: actions/github-script@3a2844b7e9c422d3c10d287c895573f7108da1b3 # v9.0.0 with: script: | - const scan = require('./.github/scripts/pr-malware-scan.js'); + const scan = require('./.github/scripts/pr-malware-scan.cjs'); await scan({ github, context, core }); diff --git a/ROADMAP.md b/ROADMAP.md index f2aad947..5fd27ccc 100644 --- a/ROADMAP.md +++ b/ROADMAP.md @@ -125,13 +125,13 @@ for status and issue links. ## Phase 9 — Deploy & CI **Status: Not started for real production. A Render free-tier preview exists — see note. Remaining items scoped into issues #21–#22.** -- [x] **PR malware scan** — `.github/workflows/pr-malware-scan.yml` + `.github/scripts/pr-malware-scan.js`, on every PR push. Flags editor/devcontainer autorun tasks, npm install hooks, typosquatted packages and Actions, non-registry dependency sources, payloads disguised as fonts/images, base64/whitespace obfuscation, exfiltration endpoints, reverse shells and miners. HIGH findings fail the `Malware scan` check, label the PR `security-review` and @mention the author; one comment per PR, updated in place. Reads the PR as data only (never checks out or runs it). Added 2026-10-20 after a VS Code autorun payload (escrow #163) and a typosquatted action (escrow #176). +- [x] **PR malware scan** — `.github/workflows/pr-malware-scan.yml` + `.github/scripts/pr-malware-scan.cjs`, on every PR push. Flags editor/devcontainer autorun tasks, npm install hooks, typosquatted packages and Actions, non-registry dependency sources, payloads disguised as fonts/images, base64/whitespace obfuscation, exfiltration endpoints, reverse shells and miners. HIGH findings fail the `Malware scan` check, label the PR `security-review` and @mention the author; one comment per PR, updated in place. Reads the PR as data only (never checks out or runs it). Added 2026-10-20 after a VS Code autorun payload (escrow #163) and a typosquatted action (escrow #176). - [ ] Choose deployment target (ARCHITECTURE.md §8 open decision) — record as an ADR. **Still not resolved.** A Render free-tier web service + Postgres now runs `backend/`, so `docforum-web`'s GitHub Pages preview has a live API to call — see `docs/adr/0003-render-preview-deployment.md`. This is explicitly a preview, not the production decision: no secrets manager, no backups, no staging/prod split, free-tier Postgres expires 2026-11-06 (renewed 2026-10-07; 30 days, 14-day grace period) unless recreated/upgraded before then — renewal steps in ADR 0003's "Renewing the free database" section. Tracked as [issue #22](https://github.com/DocForum/docforum-core/issues/22) (Medium, 150 pts). - [x] Real CI pipeline (replaced `.github/workflows/ci.yml` placeholder — was `pull_request`-only, `echo "TODO"`, never once run). Now runs on push to `main` and on PRs: `npm audit --omit=dev` at high severity (`audit:prod`, Phase 8 issue #47) → `prisma:generate` → `typecheck` → unit tests → **integration tests (the self-contained embedded-Postgres double-booking proof)** → `build`. Verified locally end-to-end before pushing (14 unit + 1 integration test passing) and confirmed green in Actions. No lint script exists yet in `backend/package.json` — not added; `tsc --noEmit` is the closest static check currently available. Lint now tracked as [issue #28](https://github.com/DocForum/docforum-core/issues/28) (Trivial, 100 pts). Closes [issue #21](https://github.com/DocForum/docforum-core/issues/21) (Medium, 150 pts). - [ ] Staging environment. Blocked on issue #22's decision landing first — not yet scoped into its own issue. - [ ] Production environment + secrets management. Blocked on issue #22's decision landing first — not yet scoped into its own issue. - [x] Docs site deployed — `docs/site/` (VitePress) via `.github/workflows/deploy-docs.yml`, live at https://docforum.github.io/docforum-core/. Unrelated to the production-deploy decision above; this is a static site with no backend of its own. -- [x] **PR conflict notifier** — `.github/workflows/pr-conflict-notifier.yml` + `.github/scripts/pr-conflict-notifier.js`. On every push to `main` (and every 3h) it labels open PRs that conflict with `main` as `needs-rebase` and @mentions the author once per push with rebase steps; the label clears itself when the conflict is resolved. Runs from `main` only and never checks out PR code. +- [x] **PR conflict notifier** — `.github/workflows/pr-conflict-notifier.yml` + `.github/scripts/pr-conflict-notifier.cjs`. On every push to `main` (and every 3h) it labels open PRs that conflict with `main` as `needs-rebase` and @mentions the author once per push with rebase steps; the label clears itself when the conflict is resolved. Runs from `main` only and never checks out PR code. ## Explicitly deferred (not on this roadmap, tracked so they aren't forgotten) - In-app video/voice consultation (PRD OQ-1 — v1 assumes in-person + async messaging).