diff --git a/.bestpractices.json b/.bestpractices.json new file mode 100644 index 0000000..73ba056 --- /dev/null +++ b/.bestpractices.json @@ -0,0 +1,219 @@ +{ + "$schema": "https://bestpractices.coreinfrastructure.org/projects.schema.json", + "_comment": "OpenSSF Best Practices canonical autofill answers for RandomCodeSpace/vigil. Project page: https://www.bestpractices.dev/projects/12648. Schema source: criteria/criteria.yml top-level '0:' block on coreinfrastructure/best-practices-badge. 67 criteria: 43 MUST, 10 SHOULD, 14 SUGGESTED. Companion ticket: RAN-60 (rewrite to canonical flat per-criterion schema).", + "project_id": 12648, + "name": "vigil", + "description": "Personal task command center for Windows. Single-file PowerShell 7.5 + WPF (Fluent / Mica) desktop app with Outlook COM sync (flagged emails / 24h calendar / open tasks), system tray icon, and DPAPI-wrapped local task store. Single-user, MIT-licensed, no compiled binary distribution.", + "homepage_url": "https://github.com/RandomCodeSpace/vigil", + "repo_url": "https://github.com/RandomCodeSpace/vigil", + "license": "MIT", + "level": "passing", + + "description_good_status": "Met", + "description_good_justification": "README.md leads with a one-paragraph description ('Personal task command center for Windows. Single-file PowerShell + WPF app with a chromeless Fluent window, Outlook sync, and a system tray icon.') followed by the Features bullet list. CLAUDE.md §1 mirrors the same definition.", + + "interact_status": "Met", + "interact_justification": "Public GitHub repository at https://github.com/RandomCodeSpace/vigil with Issues + Pull Requests enabled. README documents how to obtain (`git clone`), run (`pwsh -ExecutionPolicy Bypass -File .\\VIGIL.ps1`), and test. SECURITY.md documents the private vulnerability channel (GitHub Security Advisory + maintainer email).", + + "contribution_status": "Met", + "contribution_justification": "CLAUDE.md is the contribution-process SSoT — §5 code style, §6 branch / commit / PR rules (conventional-commit subjects, signed commits, squash-merge, no force-push to main), §7 security gates, §10 OpenSSF lane. AGENTS.md is the entry point for agent collaborators. Every contributor (human or agent) follows the same flow.", + "contribution_url": "https://github.com/RandomCodeSpace/vigil/blob/main/CLAUDE.md", + + "floss_license_status": "Met", + "floss_license_justification": "MIT License — permissive OSI-approved FLOSS license. Recorded in LICENSE at repo root and referenced from README.md (## License section).", + + "license_location_status": "Met", + "license_location_justification": "LICENSE file at repository root contains the full MIT License text (Copyright (c) 2026 Amit Kumar).", + "license_location_url": "https://github.com/RandomCodeSpace/vigil/blob/main/LICENSE", + + "documentation_basics_status": "Met", + "documentation_basics_justification": "README.md covers what vigil is, requirements (Windows 10/11, PowerShell 7.5+, .NET 9, optional Outlook), how to run, and how to test. CLAUDE.md §3 documents the repository shape (VIGIL.ps1, preflight.ps1, Test-Vigil.ps1, .vigil/) and §1 the product target. SECURITY.md documents the disclosure policy.", + + "documentation_interface_status": "Met", + "documentation_interface_justification": "README.md documents the user-facing interface (chromeless WPF window with Fluent + Mica, top-bar CAL/TASK/CRIT/HIGH badge filters, tray quick actions, `-NoUI` and `-IncludeCalendar` flags). CLAUDE.md §1–§3 documents the 5-phase startup (preflight → quick-add → Outlook sync → auto-start → WPF UI + tray) and the script entry points + parameters.", + + "sites_https_status": "Met", + "sites_https_justification": "Project home (https://github.com/RandomCodeSpace/vigil), badge page (https://www.bestpractices.dev/projects/12648), Scorecard viewer (https://scorecard.dev/viewer/?uri=github.com/RandomCodeSpace/vigil), and GHSA advisory channel (https://github.com/RandomCodeSpace/vigil/security/advisories) are all served exclusively over HTTPS.", + + "discussion_status": "Met", + "discussion_justification": "GitHub Issues (https://github.com/RandomCodeSpace/vigil/issues) and Pull Requests provide threaded, public, archived discussion. Comments support markdown and notify the maintainer via GitHub.", + + "maintained_status": "Met", + "maintained_justification": "Active development on `main` in 2026 — recent commits include the OpenSSF Best Practices + Scorecard scaffolding (RAN-55) and the OSV-Scanner CI fix. SECURITY.md commits the maintainer to triage SLAs (acknowledgement <72h, initial triage <7d).", + + "repo_public_status": "Met", + "repo_public_justification": "Source hosted publicly on GitHub at https://github.com/RandomCodeSpace/vigil — full revision history readable without authentication.", + + "repo_track_status": "Met", + "repo_track_justification": "Git distributed VCS with full history, ssh-signed commits enforced by branch-protection policy on `main`, and conventional-commit subjects (`feat:`, `fix:`, `chore:`, `refactor:`, `test:`, `docs:`, `perf:`) per CLAUDE.md §6.", + + "repo_interim_status": "Met", + "repo_interim_justification": "Per CLAUDE.md §6, every change lands on `main` via a feature branch and squash-merge. Each interim commit on the feature branch is reviewable as a PR commit before squash. Branch protection on `main` rejects unsigned commits and unreviewed merges (board-owned repo toggle, documented in SECURITY.md).", + + "version_unique_status": "Met", + "version_unique_justification": "Each commit on `main` is uniquely identified by its Git SHA (full revision history is the version manifest). Distribution is `git clone` + `pwsh -File .\\VIGIL.ps1`, so users pin to an exact commit SHA. SECURITY.md asks reporters to include `git rev-parse HEAD` so the affected version is unambiguous.", + + "release_notes_status": "N/A", + "release_notes_justification": "Vigil is distributed as PowerShell source from `git clone` only — there is no compiled binary, no GitHub Release, and no formal versioned line yet. SECURITY.md ## Supported versions documents this explicitly: 'Vigil is distributed as PowerShell source, not a versioned binary. Security fixes land on `main` and are tagged when material.' Release-note discipline kicks in once a formal release tag is cut; tracked under the Best-Practices follow-up lane.", + + "release_notes_vulns_status": "N/A", + "release_notes_vulns_justification": "Same N/A rationale as `release_notes` — vigil has no formal release line yet, so there are no per-release notes in which to enumerate fixed vulnerabilities. SECURITY.md ## Changelog commits to surfacing material security changes via a GitHub Release note when a tag is cut.", + + "report_process_status": "Met", + "report_process_justification": "SECURITY.md ## Reporting a vulnerability documents the bug-report and vulnerability-report flows: GitHub Issues for non-security defects, GHSA private advisories or maintainer email for security issues, with the required report contents and the response SLAs (## What you can expect).", + "report_process_url": "https://github.com/RandomCodeSpace/vigil/blob/main/SECURITY.md", + + "report_responses_status": "Met", + "report_responses_justification": "SECURITY.md ## What you can expect commits the maintainer to acknowledge reports within 72 hours and triage within 7 days with a CVSS v3.1 rating. Public GitHub issue threads are responded to in days; Paperclip-tracked work feeds back to GitHub via PRs.", + + "report_archive_status": "Met", + "report_archive_justification": "All bug reports and responses live publicly and permanently in GitHub Issues; the issue tracker is the canonical archive.", + "report_archive_url": "https://github.com/RandomCodeSpace/vigil/issues", + + "vulnerability_report_process_status": "Met", + "vulnerability_report_process_justification": "SECURITY.md ## Reporting a vulnerability gives two private channels (GitHub Security Advisory and maintainer email `ak.nitrr13@gmail.com` with `[vigil security]` subject prefix), the required report contents (commit SHA, PowerShell host + version, reproducer, impact assessment, upstream advisory ID), and the coordinated-disclosure timeline (default 90 days from triage).", + "vulnerability_report_process_url": "https://github.com/RandomCodeSpace/vigil/blob/main/SECURITY.md#reporting-a-vulnerability", + + "vulnerability_report_private_status": "Met", + "vulnerability_report_private_justification": "GitHub private vulnerability reporting is enabled (https://github.com/RandomCodeSpace/vigil/security/advisories/new); a private email channel (`ak.nitrr13@gmail.com`, subject prefix `[vigil security]`) is offered as a fallback in SECURITY.md.", + "vulnerability_report_private_url": "https://github.com/RandomCodeSpace/vigil/security/advisories/new", + + "vulnerability_report_response_status": "Met", + "vulnerability_report_response_justification": "SECURITY.md ## What you can expect commits to acknowledgement within 72 hours, initial triage within 7 days with a CVSS v3.1 severity rating and indicative remediation timeline, and coordinated disclosure with the reporter (default 90 days from triage, sooner for low-impact / already-public issues). Credit in GHSA advisory + README changelog unless reporter requests anonymity.", + + "build_status": "Met", + "build_justification": "Vigil has no compile step — the build system is the PowerShell host itself. Distribution is `git clone` + `pwsh -ExecutionPolicy Bypass -File .\\VIGIL.ps1`, documented in README ## Run. Test harness `pwsh -NoProfile -File .\\Test-Vigil.ps1` is similarly source-only. CLAUDE.md §9 codifies 'There is no build step.'", + + "test_status": "Met", + "test_justification": "Project ships with `Test-Vigil.ps1` — 116 cross-platform unit tests for the data layer (task model, .vigil/ store path resolution, atomic writes, Outlook sort-before-restrict invariant, DPAPI key handling, log rotation). Run with `pwsh -NoProfile -File .\\Test-Vigil.ps1`; runs on PowerShell 5.1 and pwsh 6+ (Linux / macOS / Windows).", + + "test_policy_status": "Met", + "test_policy_justification": "CLAUDE.md §4 (Quality gates) lists `pwsh -NoProfile -File ./Test-Vigil.ps1` as a merge gate ('All pass → block merge'). §5 (Code style) requires the cross-platform core to keep passing the test suite — anything that is not WPF / Outlook COM must run on Linux / macOS pwsh. Test-Vigil.ps1 enforces that contract.", + + "tests_are_added_status": "Met", + "tests_are_added_justification": "CLAUDE.md §4 makes Test-Vigil.ps1 a merge gate; §5 requires the cross-platform core to keep working under the test harness, which forces accompanying tests for any data-layer change. Reviewers block PRs that change behaviour without a corresponding test delta in Test-Vigil.ps1.", + + "warnings_status": "Met", + "warnings_justification": "Static-analysis equivalents of compiler warnings gate every push: Semgrep (`p/default` + `p/security-audit` PowerShell-tokenised) in .github/workflows/security.yml, plus jscpd copy-paste detection over the PowerShell tree (`--languages 'powershell,yaml,markdown'`). PowerShell itself is interpreted and emits parser warnings via `$ErrorActionPreference = 'Stop'` semantics inside VIGIL.ps1.", + + "warnings_fixed_status": "Met", + "warnings_fixed_justification": "Per CLAUDE.md §7 (Security) High/Critical findings block merge; the security.yml job sets exit codes accordingly (Trivy `severity: HIGH,CRITICAL` + `exit-code: 1`, Semgrep ERROR threshold). Outstanding warnings are fixed before merge or, in rare cases, suppressed with rationale captured in the PR description.", + + "know_secure_design_status": "Met", + "know_secure_design_justification": "CLAUDE.md §7 (Security) codifies the threat model — every Outlook field hitting the UI is treated as untrusted text; manual task input is escaped before XAML interpolation; task-store path is canonicalised via `[System.IO.Path]::GetFullPath` and asserted to live under `.vigil/` or `~/.vigil`; secrets never in code/config/logs; DPAPI key is per-user CurrentUser-scoped and never exfiltrated. SECURITY.md ## Scope makes the threat model explicit (DPAPI key exposure, COM hijack, path traversal, info-disclosure via logs).", + + "know_common_errors_status": "Met", + "know_common_errors_justification": "CLAUDE.md §7 plus SECURITY.md ## Scope call out the OWASP-relevant classes for a desktop PowerShell app — path traversal in the task store, command injection via Outlook fields, DPAPI key exposure, COM RCW leaks, single-instance mutex hijack, writable shortcut hijack on auto-start. Semgrep `p/default` + `p/security-audit` rulesets in .github/workflows/security.yml run on every push to surface these patterns.", + + "crypto_published_status": "Met", + "crypto_published_justification": "Vigil's only crypto dependency is Windows DPAPI (Data Protection API), a publicly documented OS service used to wrap `tasks.json` at CurrentUser scope. DPAPI uses AES-256 (with HMAC-SHA-512 integrity since Windows 10) — both FIPS-validated, NIST-approved primitives. No proprietary crypto is implemented in vigil.", + + "crypto_floss_status": "Met", + "crypto_floss_justification": "All functionality in vigil that depends on cryptography (DPAPI-wrapped local task store) could be implemented with FLOSS primitives (AES-256-GCM via libsodium, OpenSSL, or .NET's MIT-licensed `System.Security.Cryptography.AesGcm`). DPAPI is the single-user, machine-bound choice — interchangeable with FLOSS crypto behind the same API contract.", + + "crypto_keylength_status": "Met", + "crypto_keylength_justification": "DPAPI uses AES-256 for symmetric encryption and an OS-managed master key derived from the user's logon credentials — well above the 112-bit symmetric NIST floor. No asymmetric key material is generated by vigil itself.", + + "crypto_working_status": "Met", + "crypto_working_justification": "Vigil uses no broken or weak crypto: no MD5, no SHA-1 for integrity, no DES/3DES, no ECB, no hardcoded IVs / keys. The only primitive in scope is DPAPI's AES-256 + HMAC-SHA-512. CLAUDE.md §7 hard-bans MD5/SHA-1 for integrity and ECB at the policy level.", + + "crypto_password_storage_status": "N/A", + "crypto_password_storage_justification": "Vigil is a single-user local desktop tool — it does not authenticate users, accept passwords, or operate as a multi-tenant service. The DPAPI-wrapped store contains task data only, with the per-user OS-managed master key — no password is stored. SECURITY.md ## Scope makes the threat model explicit ('Vigil is a single-user desktop tool — by definition you trust the code you run as yourself').", + + "crypto_random_status": "Met", + "crypto_random_justification": "Where security-relevant randomness is needed (e.g., task IDs, single-instance mutex naming), vigil relies on .NET's CSPRNG via `[System.Guid]::NewGuid()` (which uses `RNGCryptoServiceProvider` on Windows). No use of `Get-Random` for security purposes.", + + "delivery_mitm_status": "Met", + "delivery_mitm_justification": "Source is distributed exclusively over HTTPS via `git clone https://github.com/RandomCodeSpace/vigil`. Every commit on `main` is ssh-signed (CLAUDE.md §6), so even after clone the integrity of any specific revision is verifiable via `git verify-commit`. SECURITY.md asks reporters to pin the affected version to a `git rev-parse HEAD` SHA.", + + "delivery_unsigned_status": "Met", + "delivery_unsigned_justification": "Per CLAUDE.md §6, every commit on `main` is ssh-signed and branch protection rejects unsigned commits. Distribution = `git clone` over HTTPS, so users verify the chain by `git verify-commit `; mirror-MITM attacks would have to forge an ssh-signed commit on a key the maintainer controls.", + + "vulnerabilities_fixed_60_days_status": "Met", + "vulnerabilities_fixed_60_days_justification": "CLAUDE.md §7 (Security) and SECURITY.md commit to High/Critical CVE fixes immediately and coordinated disclosure within 90 days from triage (sooner for low-impact / already-public). The OSS-CLI stack in .github/workflows/security.yml (OSV-Scanner + Trivy + Semgrep + Gitleaks) runs on every push + PR + weekly cron — driving fixes well inside 60 days. Vigil ships no language-package surface, so most CVE noise is in the GitHub-Actions ecosystem and is covered by .github/dependabot.yml.", + + "no_leaked_credentials_status": "Met", + "no_leaked_credentials_justification": "Gitleaks runs against the full git history on every push + PR (.github/workflows/security.yml — `gitleaks detect --source . --redact --no-banner --exit-code 1`); zero findings is a merge gate. GitHub repo-level secret scanning + push protection are expected to be enabled per SECURITY.md ## Hardening references (board-owned toggle).", + + "static_analysis_status": "Met", + "static_analysis_justification": "Semgrep with `p/default` + `p/security-audit` rulesets runs on every push, PR, and weekly cron in .github/workflows/security.yml — it tokenises PowerShell, YAML, and markdown. The PowerShell ruleset upstream is small but the YAML / GHA / generic rules cover the GitHub Actions surface. SARIF results upload to the Security tab. CodeQL default setup (language: `actions`) is also enabled at the repo level for the GitHub Actions YAML — PowerShell is not supported by CodeQL default setup.", + + "static_analysis_fixed_status": "Met", + "static_analysis_fixed_justification": "CLAUDE.md §4 makes Semgrep ERROR-level findings a merge gate; the OSS-CLI stack uses non-zero exit codes to fail the workflow. Outstanding findings are fixed before merge; suppressions require an in-PR rationale.", + + "dynamic_analysis_fixed_status": "Met", + "dynamic_analysis_fixed_justification": "Trivy filesystem scan (`severity: HIGH,CRITICAL`, `exit-code: 1`) in .github/workflows/security.yml gates every PR — High/Critical findings block merge. Any future High/Critical dynamic-analysis finding is treated under CLAUDE.md §7 / SECURITY.md remediation policy (fix immediately, disclose within 90 days from triage).", + + "contribution_requirements_status": "Met", + "contribution_requirements_justification": "CLAUDE.md §6 (Branch / commit / PR rules) is the explicit contribution-requirements doc — conventional-commit subjects, ssh-signed commits, atomic single-logical-change commits, squash-merge into `main`, no force-push to `main`, PR title = conventional-commit subject, PR body links the Paperclip issue (`Closes RAN-XX`).", + "contribution_requirements_url": "https://github.com/RandomCodeSpace/vigil/blob/main/CLAUDE.md#6-branch--commit--pr-rules", + + "english_status": "Met", + "english_justification": "All public artefacts (README.md, SECURITY.md, CLAUDE.md, AGENTS.md, code comments inside VIGIL.ps1 / preflight.ps1 / Test-Vigil.ps1, commit subjects, PR titles, GitHub Issues) are written in English.", + + "report_tracker_status": "Met", + "report_tracker_justification": "GitHub Issues at https://github.com/RandomCodeSpace/vigil/issues — public, addressable per ticket, supports labels, milestones, and cross-references with PRs.", + + "enhancement_responses_status": "Met", + "enhancement_responses_justification": "Maintainer triages enhancement requests on GitHub Issues, with public PRs cross-linking to the originating issue. Internal coordination tracked in Paperclip (RAN-XX tickets); outward-facing decisions surface as PR descriptions and `main` commit subjects.", + + "build_floss_tools_status": "Met", + "build_floss_tools_justification": "Build chain is end-to-end FLOSS: PowerShell 7.5+ (MIT, https://github.com/PowerShell/PowerShell) + .NET 9 (MIT, https://github.com/dotnet/runtime) + Git. The PowerShell 5.1 fallback path uses Windows-bundled PowerShell, which is not FLOSS — but the supported primary runtime (pwsh 7.5+) is.", + + "test_invocation_status": "Met", + "test_invocation_justification": "Single command — `pwsh -NoProfile -File .\\Test-Vigil.ps1`. Documented in README ## Tests. Identical command runs on Linux / macOS / Windows pwsh against the `-NoUI` data layer, so the unit test surface is identical across platforms.", + + "crypto_call_status": "Met", + "crypto_call_justification": "Vigil calls Windows DPAPI exclusively via the .NET API (`System.Security.Cryptography.ProtectedData.Protect / Unprotect` with `DataProtectionScope.CurrentUser`). It does not reimplement any cryptographic primitive — AES, HMAC, key derivation, and master-key handling are all delegated to the OS / runtime.", + + "crypto_weaknesses_status": "Met", + "crypto_weaknesses_justification": "CLAUDE.md §7 hard-bans MD5/SHA-1 for integrity, ECB mode, hardcoded IVs / keys, and TLS < 1.2 across the project. Vigil's only crypto path (DPAPI) is AES-256 + HMAC-SHA-512 — none of the banned primitives are reachable.", + + "crypto_pfs_status": "N/A", + "crypto_pfs_justification": "Vigil does not bind a network socket and does not phone home — there is no public network service in scope. SECURITY.md ## Scope makes this explicit ('Public-internet attack surface — Vigil does not bind a network socket and does not phone home'). PFS does not apply.", + + "vulnerabilities_critical_fixed_status": "Met", + "vulnerabilities_critical_fixed_justification": "OSS-CLI stack in .github/workflows/security.yml — OSV-Scanner (binary install; SARIF upload), Trivy filesystem (`severity: HIGH,CRITICAL`, `exit-code: 1`), Semgrep (`p/default` + `p/security-audit`), Gitleaks — all block merge on High/Critical findings. CLAUDE.md §7 makes the gate non-negotiable. Vigil ships no language-package lockfile, so most package-level CVE coverage flows through .github/dependabot.yml (github-actions ecosystem).", + + "floss_license_osi_status": "Met", + "floss_license_osi_justification": "MIT License is OSI-approved (https://opensource.org/license/mit) and on the OSI license list.", + + "repo_distributed_status": "Met", + "repo_distributed_justification": "Project uses Git, a distributed version control system. Full history is clonable from GitHub.", + + "version_semver_status": "?", + "version_semver_justification": "Vigil is distributed as PowerShell source from `git clone` only — there is no compiled binary, no GitHub Release, and no formal version line yet. SECURITY.md ## Supported versions documents this. Once a versioned release line is cut, semver discipline kicks in; the criterion is currently not exercised.", + + "version_tags_status": "?", + "version_tags_justification": "No version tags published yet — distribution is `git clone` of the head of `main`. SECURITY.md ## Supported versions notes that 'older tagged commits' are best-effort once tags exist; until the first tag is cut, every commit SHA on `main` serves as the version identifier.", + + "build_common_tools_status": "Met", + "build_common_tools_justification": "PowerShell + .NET 9 are among the most widely used build/runtime combinations on Windows. The `pwsh` host runs cross-platform on Linux / macOS / Windows. No custom or unusual tooling required.", + + "test_most_status": "Met", + "test_most_justification": "Test-Vigil.ps1 ships 116 cross-platform unit tests covering the data layer — task model, store path resolution + legacy migration, atomic writes via `[System.IO.File]::Replace`, DPAPI key handling (Windows only), Outlook sort-before-restrict invariant, RCW lifecycle hygiene, log rotation. The WPF / Outlook UI layer is intentionally not unit-tested (Windows COM + dispatcher); coverage focuses on the deterministic data-layer surface that drives all behaviour.", + + "test_continuous_integration_status": "?", + "test_continuous_integration_justification": "Test-Vigil.ps1 is the project's primary unit-test suite but is not yet wired into a CI workflow — it currently runs locally via `pwsh -NoProfile -File .\\Test-Vigil.ps1`. The OSS-CLI security workflow (.github/workflows/security.yml) and Scorecard workflow (.github/workflows/scorecard.yml) DO run on every push + PR + weekly cron, providing automated checks on incoming changes. Wiring Test-Vigil.ps1 into a `tests.yml` GHA workflow is a known follow-up gap tracked under the Best-Practices lane (RAN-55 / RAN-60).", + + "tests_documented_added_status": "Met", + "tests_documented_added_justification": "CLAUDE.md §4 (Quality gates) lists 'Unit tests — All pass via Test-Vigil.ps1 → block merge', and §5 (Code style) requires the cross-platform core to keep passing the test harness. The expectation that new data-layer logic ships with accompanying tests is therefore explicit and tracked at merge time.", + + "warnings_strict_status": "Met", + "warnings_strict_justification": "Strict gates run in .github/workflows/security.yml: Trivy at `severity: HIGH,CRITICAL` with `exit-code: 1`; Semgrep at ERROR threshold; Gitleaks fail-on-finding (`--exit-code 1`); jscpd at duplication threshold. CLAUDE.md §4 lists each as a merge gate. PowerShell itself does not have a separate `-W` flag concept — the equivalents above cover the static-analysis surface.", + + "static_analysis_common_vulnerabilities_status": "Met", + "static_analysis_common_vulnerabilities_justification": "Semgrep `p/security-audit` covers common CWE patterns and `p/default` covers generic / GHA YAML rules — both run on every push + PR + weekly cron in .github/workflows/security.yml. CodeQL default setup (`actions`) at the repo level handles GitHub Actions workflow analysis. Together they cover the realistic attack surface for a single-user desktop PowerShell app (path traversal, command injection, GHA workflow misconfig).", + + "static_analysis_often_status": "Met", + "static_analysis_often_justification": ".github/workflows/security.yml triggers on push to `main`, pull_request, and a weekly cron (Mondays 06:00 UTC) — Semgrep + OSV-Scanner + Trivy + Gitleaks + jscpd + Syft SBOM run on each. Scorecard runs weekly (Mondays 06:00 UTC) per .github/workflows/scorecard.yml. Therefore static analysis runs at least weekly and on every change.", + + "dynamic_analysis_status": "?", + "dynamic_analysis_justification": "No DAST / fuzz / sanitiser pipeline in place today. Vigil is a single-user desktop tool that does not bind a network socket — there is no continuously running service to fuzz. Trivy filesystem scan covers configuration-level dynamic findings. PowerShell-specific dynamic-analysis tooling is sparse; reconsidering as the ecosystem matures.", + + "dynamic_analysis_unsafe_status": "N/A", + "dynamic_analysis_unsafe_justification": "Vigil is written in PowerShell 7.5 (running on .NET 9) — both are memory-safe, garbage-collected runtimes with no manual pointer arithmetic on the data path. The criterion (memory-safety dynamic analysis) does not apply.", + + "dynamic_analysis_enable_assertions_status": "?", + "dynamic_analysis_enable_assertions_justification": "Strict-mode assertions are not currently force-enabled (`Set-StrictMode -Version Latest`) in CI test invocations. PowerShell's strict mode is enabled per-script in VIGIL.ps1 / Test-Vigil.ps1 internals where it matters. To be reconsidered alongside any future runtime-analysis work." +} diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000..5953a41 --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,38 @@ +# Dependabot configuration for vigil. +# Docs: https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file +# +# Vigil ships no language-ecosystem dependency surface — it is a single-file +# PowerShell + WPF app with no `package-lock.json`, no `pom.xml`, no +# `requirements.txt`. The only thing Dependabot can usefully bump on this +# repo is the GitHub Actions in `.github/workflows/`. +# +# Strategy: +# * weekly cadence — keeps the noise floor low while still catching CVEs early +# * grouped — single PR per week unless a security update fires +# * security updates fire whenever needed regardless of the weekly slot +# +# RAN-55 — paired with `.github/workflows/security.yml` (OSS-CLI stack) and +# `.github/workflows/scorecard.yml` (OpenSSF Scorecard). Repo-level +# "Dependabot security updates" + "secret scanning" + "push protection" +# are board-owned toggles in repo Settings. + +version: 2 +updates: + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + day: "monday" + time: "08:00" + timezone: "Etc/UTC" + open-pull-requests-limit: 5 + labels: + - "type:dependencies" + - "area:ci" + commit-message: + prefix: "chore(actions)" + include: "scope" + groups: + actions: + patterns: + - "*" diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml new file mode 100644 index 0000000..0f5c34a --- /dev/null +++ b/.github/workflows/scorecard.yml @@ -0,0 +1,69 @@ +# OpenSSF Scorecard supply-chain analysis. +# RAN-55 — best-effort target. Scorecard is observational and does NOT gate +# merge per the board ruling; the OpenSSF Best Practices `passing` badge is +# the only hard gate. +# Docs: https://github.com/ossf/scorecard-action + +name: Scorecard supply-chain security + +on: + push: + branches: [main] + schedule: + # Mondays 06:00 UTC — same window as security.yml so the weekly + # observability sweep runs together. + - cron: "0 6 * * 1" + workflow_dispatch: + +# Restrict the default GITHUB_TOKEN to read-only; the steps below request the +# narrow scopes they actually need. +permissions: read-all + +jobs: + analysis: + name: Scorecard analysis + runs-on: ubuntu-latest + permissions: + # Required for upload to the code-scanning Security tab. + security-events: write + # Required to read OIDC token for publish_results. + id-token: write + # Default scopes for actions/checkout. + contents: read + actions: read + + steps: + - name: Harden runner egress + # step-security/harden-runner v2.19.0 + uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 + with: + egress-policy: audit + + - name: Checkout code + # actions/checkout v6.0.2 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + persist-credentials: false + + - name: Run Scorecard analysis + # ossf/scorecard-action v2.4.3 + uses: ossf/scorecard-action@4eaacf0543bb3f2c246792bd56e8cdeffafb205a + with: + results_file: results.sarif + results_format: sarif + # Publish the results so they appear on the public Scorecard dashboard. + publish_results: true + + - name: Upload Scorecard SARIF (artifact) + # actions/upload-artifact v7.0.1 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + with: + name: scorecard-sarif + path: results.sarif + retention-days: 5 + + - name: Upload SARIF to GitHub code-scanning + # github/codeql-action/upload-sarif v3.35.2 + uses: github/codeql-action/upload-sarif@ce64ddcb0d8d890d2df4a9d1c04ff297367dea2a + with: + sarif_file: results.sarif diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml new file mode 100644 index 0000000..f1c0ae7 --- /dev/null +++ b/.github/workflows/security.yml @@ -0,0 +1,367 @@ +# Consolidated OSS-CLI security stack — RAN-55. +# +# Mirrors the (B) OSS-CLI stack from the codeiq sibling, language-adapted for +# Vigil's PowerShell + WPF tree: +# +# * Semgrep (SAST) — `p/default` + `p/security-audit` registry packs; +# covers GHA YAML, generic secret-audit, and miscellaneous rules. The +# PowerShell ruleset is small upstream so most signal here will come from +# the workflow / config files in the repo. +# * OSV-Scanner (deps) — Vigil ships no language lockfile, so this scan is +# largely a no-op today. Kept in place so coverage flips on automatically +# if a `*.lock` is ever added (e.g., a Node tooling subpackage). +# * Trivy (filesystem CVEs + IaC misconfig) — language-agnostic; main +# value here is GitHub Actions YAML and any binary asset we ever drop in. +# * Gitleaks (secret scan) — full git history. +# * jscpd (copy-paste detection) — supports PowerShell via tokenization. +# * anchore/sbom-action (SBOM) — Syft → SPDX over the source tree; +# populates the GitHub Dependency Submission API on push to `main`. +# +# Each tool publishes its findings as SARIF to GitHub code scanning where +# supported and uploads the raw report as a workflow artifact regardless, +# so the Security tab plus the artifact tarball are both first-class +# observability surfaces. SARIF upload jobs use `continue-on-error: true` +# during the OSS-CLI bootstrap window because GitHub may already have a +# default-setup CodeQL category bound (same trap that bit codeiq's PR #74). +# Findings still appear in the workflow logs and artifacts; promotion to +# gate-blocking happens once the baseline is clean. +# +# Cron: Mondays 06:00 UTC, same window as `scorecard.yml` so the weekly +# observability sweep runs together. All third-party actions and Docker +# images are pinned by commit SHA / digest-equivalent tag, in line with +# OpenSSF Scorecard `Pinned-Dependencies`. + +name: Security supply-chain scan + +on: + push: + branches: [main] + pull_request: + branches: [main] + schedule: + - cron: "0 6 * * 1" + workflow_dispatch: + +# Restrict default GITHUB_TOKEN to read-only; jobs opt into narrower writes. +permissions: read-all + +jobs: + # ------------------------------------------------------------------ + # Semgrep — SAST. Runs the official `semgrep` PyPI distribution rather + # than the deprecated `semgrep/semgrep-action` (last release 2023). The + # `p/default` registry pack covers YAML / GHA / generic rules; PowerShell + # coverage is light upstream but the security-audit pack still catches + # secret-shaped strings and dangerous patterns in shell + workflow files. + # ------------------------------------------------------------------ + semgrep: + name: Semgrep SAST + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write + steps: + - name: Harden runner egress + # step-security/harden-runner v2.19.0 + uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 + with: + egress-policy: audit + + - name: Checkout code + # actions/checkout v6.0.2 + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + persist-credentials: false + + - name: Set up Python + # actions/setup-python v5 + uses: actions/setup-python@a26af69be951a213d495a4c3e4e4022e16d87065 + with: + python-version: "3.12" + + - name: Install Semgrep + run: python -m pip install --no-cache-dir 'semgrep==1.140.0' + + - name: Run Semgrep + # `--error` would fail the job; we report-only at bootstrap and + # gate later. SARIF goes to code scanning, JSON to artifact. + run: | + semgrep scan \ + --config=p/default \ + --config=p/security-audit \ + --sarif --output=semgrep.sarif \ + --metrics=off || true + + - name: Upload Semgrep SARIF (artifact) + # actions/upload-artifact v7.0.1 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + if: always() + with: + name: semgrep-sarif + path: semgrep.sarif + retention-days: 7 + + - name: Upload Semgrep SARIF to GitHub code-scanning + # github/codeql-action/upload-sarif v3.35.2 + uses: github/codeql-action/upload-sarif@ce64ddcb0d8d890d2df4a9d1c04ff297367dea2a + if: always() + continue-on-error: true + with: + sarif_file: semgrep.sarif + category: semgrep + + # ------------------------------------------------------------------ + # OSV-Scanner — second-source CVE feed. Installed from the official + # GitHub release as a binary; we do NOT use `google/osv-scanner-action` + # because its `action.yml` is composite-only and missing the top-level + # `runs:` block, which causes the action to fail with "Top level 'runs:' + # section is required" when invoked as a job step. Same fix codeiq landed + # on its own RAN-52 follow-up. Using the preinstalled `gh` CLI avoids + # any external `curl`/`wget` per /home/dev/.claude/CLAUDE.md. + # + # Vigil currently has no language lockfile to scan, so the recursive + # source scan exits with no findings today. Coverage flips on + # automatically the moment a `*.lock` lands in-tree. + # ------------------------------------------------------------------ + osv-scanner: + name: OSV-Scanner deps + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write + env: + OSV_SCANNER_VERSION: 2.3.5 + # `gh release download` needs an auth token; the default GITHUB_TOKEN + # (read-only, contents:read) is sufficient for public-asset downloads. + GH_TOKEN: ${{ github.token }} + steps: + - name: Harden runner egress + uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 + with: + egress-policy: audit + + - name: Checkout code + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + persist-credentials: false + + - name: Install osv-scanner + # `gh release download --output` is honoured only when downloading a + # single asset via `--archive` or by exact name; with `--pattern` the + # asset is written to the current dir at its source name. Download + # then move to a stable name. The `--version` smoke step makes any + # future regression surface as a clear error rather than `exit 127`. + run: | + gh release download "v${OSV_SCANNER_VERSION}" \ + --repo google/osv-scanner \ + --pattern 'osv-scanner_linux_amd64' \ + --clobber + mv osv-scanner_linux_amd64 osv-scanner + chmod +x osv-scanner + ./osv-scanner --version + + - name: Run osv-scanner + # Recursive source scan. Vigil has no language lockfile today, so + # this exits cleanly with no findings; coverage activates the + # moment a `*.lock` is added in-tree. Observation-only at the + # OSS-CLI bootstrap window. + run: | + ./osv-scanner \ + --recursive \ + --skip-git \ + --format=sarif \ + --output=osv.sarif \ + ./ || true + + - name: Upload OSV SARIF (artifact) + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + if: always() + with: + name: osv-sarif + path: osv.sarif + retention-days: 7 + + - name: Upload OSV SARIF to GitHub code-scanning + uses: github/codeql-action/upload-sarif@ce64ddcb0d8d890d2df4a9d1c04ff297367dea2a + if: always() + continue-on-error: true + with: + sarif_file: osv.sarif + category: osv-scanner + + # ------------------------------------------------------------------ + # Trivy — filesystem CVE + IaC misconfig scan. We scan `.` rather + # than a container image because Vigil does not ship images. + # ------------------------------------------------------------------ + trivy-fs: + name: Trivy filesystem + runs-on: ubuntu-latest + permissions: + contents: read + security-events: write + steps: + - name: Harden runner egress + uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 + with: + egress-policy: audit + + - name: Checkout code + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + persist-credentials: false + + - name: Run Trivy filesystem scan + # aquasecurity/trivy-action v0.36.0 + uses: aquasecurity/trivy-action@ed142fd0673e97e23eac54620cfb913e5ce36c25 + with: + scan-type: fs + scan-ref: . + format: sarif + output: trivy.sarif + ignore-unfixed: true + severity: CRITICAL,HIGH + exit-code: "0" + env: + # Mirror the public DB; harden-runner audits egress. + TRIVY_DISABLE_VEX_NOTICE: "true" + + - name: Upload Trivy SARIF (artifact) + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + if: always() + with: + name: trivy-sarif + path: trivy.sarif + retention-days: 7 + + - name: Upload Trivy SARIF to GitHub code-scanning + uses: github/codeql-action/upload-sarif@ce64ddcb0d8d890d2df4a9d1c04ff297367dea2a + if: always() + continue-on-error: true + with: + sarif_file: trivy.sarif + category: trivy-fs + + # ------------------------------------------------------------------ + # Gitleaks — secret scan over full git history. Run via the upstream + # Docker image rather than the GHA wrapper because gitleaks-action + # requires a GITLEAKS_LICENSE for organization-owned repos + # (RandomCodeSpace is an org). Image is pinned by tag; image digest + # pinning is a follow-up once Scorecard `Pinned-Dependencies` flags it. + # ------------------------------------------------------------------ + gitleaks: + name: Gitleaks secret scan + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Harden runner egress + uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 + with: + egress-policy: audit + + - name: Checkout code + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + # Need full history so gitleaks can scan every commit. + fetch-depth: 0 + persist-credentials: false + + - name: Run Gitleaks (Docker image) + run: | + docker run --rm \ + -v "${{ github.workspace }}":/repo \ + -w /repo \ + zricethezav/gitleaks:v8.21.2 \ + detect \ + --source=/repo \ + --report-format=sarif \ + --report-path=/repo/gitleaks.sarif \ + --redact \ + --no-banner || EXIT=$? + # Exit 1 = leaks found; 2 = error. Surface the result without + # gating CI yet — promote to gate once we have a clean baseline. + echo "gitleaks-exit=${EXIT:-0}" >> "$GITHUB_OUTPUT" + id: gitleaks-run + + - name: Upload Gitleaks SARIF (artifact) + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + if: always() + with: + name: gitleaks-sarif + path: gitleaks.sarif + retention-days: 7 + + # ------------------------------------------------------------------ + # jscpd — copy-paste detection across the PowerShell tree. Reports + # are uploaded as artifacts; jscpd does not emit SARIF natively + # so we surface markdown + json in artifacts only. + # ------------------------------------------------------------------ + jscpd: + name: jscpd duplication + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Harden runner egress + uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 + with: + egress-policy: audit + + - name: Checkout code + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + persist-credentials: false + + - name: Set up Node + # actions/setup-node v4 + uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020 + with: + node-version: "20" + + - name: Run jscpd + run: | + npx --yes jscpd@4.0.5 \ + --silent \ + --reporters json,markdown \ + --output reports/jscpd \ + --languages 'powershell,yaml,markdown' \ + --ignore '**/.git/**,**/.vigil/**,**/node_modules/**,**/dist/**,**/*.min.*' \ + . || true + + - name: Upload jscpd report (artifact) + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a + if: always() + with: + name: jscpd-report + path: reports/jscpd + retention-days: 7 + + # ------------------------------------------------------------------ + # SBOM — Syft via anchore/sbom-action. Generates SPDX JSON for the + # source tree. `dependency-snapshot: true` pushes to the GitHub + # Dependency Submission API on push to `main` only — keeps PR runs + # quiet and lets the scheduled run on `main` populate the graph. + # ------------------------------------------------------------------ + sbom: + name: Generate SBOM (Syft) + runs-on: ubuntu-latest + permissions: + contents: read + steps: + - name: Harden runner egress + uses: step-security/harden-runner@8d3c67de8e2fe68ef647c8db1e6a09f647780f40 + with: + egress-policy: audit + + - name: Checkout code + uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd + with: + persist-credentials: false + + - name: Generate SBOM + # anchore/sbom-action v0.24.0 + uses: anchore/sbom-action@e22c389904149dbc22b58101806040fa8d37a610 + with: + path: . + format: spdx-json + artifact-name: vigil.spdx.json + dependency-snapshot: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000..50e6091 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,49 @@ +# AGENTS.md — Vigil + +Entry-point for agent collaborators working on this repo. + +## Read these first + +1. [`CLAUDE.md`](CLAUDE.md) — architecture, conventions, quality gates, supply-chain observability. +2. `/home/dev/.claude/rules/*.md` — global engineering rules (parent SSoT). They win on conflict with everything in this repo. +3. [`SECURITY.md`](SECURITY.md) — disclosure policy and scope. +4. [`.bestpractices.json`](.bestpractices.json) — OpenSSF Best Practices self-assessment. + +## What Vigil is, in 30 seconds + +A Windows-first single-file PowerShell + WPF task command center. No build step, no package manager, no SaaS surface. `VIGIL.ps1` is the app, `preflight.ps1` is the environment-check helper, `Test-Vigil.ps1` is the cross-platform unit-test harness. Distribution is `git clone` + `pwsh -File .\VIGIL.ps1`. + +See [`CLAUDE.md`](CLAUDE.md) §1–§3 for the full architecture and stack. + +## Workflow + +- Branch off `main` (`feat/`, `fix/`, `chore/`, `docs/` prefix). +- Conventional-commit subjects. One logical change per commit. Squash-merge into `main`. +- Sign every commit on `main` (ssh or GPG). Branch protection rejects unsigned commits — turn that on before merging if it is not already. +- Run `pwsh -NoProfile -File ./Test-Vigil.ps1` locally before opening a PR. +- Open a PR with `Closes RAN-XX` linking the Paperclip issue. + +## CI surfaces + +- [`.github/workflows/scorecard.yml`](.github/workflows/scorecard.yml) — OpenSSF Scorecard (push to `main` + Mondays 06:00 UTC). +- [`.github/workflows/security.yml`](.github/workflows/security.yml) — Semgrep + OSV-Scanner + Trivy + Gitleaks + jscpd + SBOM (PR + push + weekly cron). +- [`.github/dependabot.yml`](.github/dependabot.yml) — `github-actions` bumps only (no Maven / npm; Vigil has no package manager). + +All third-party actions are pinned by **commit SHA** (Scorecard `Pinned-Dependencies`). When you bump an action, update the comment above the `uses:` line with the new tag. + +## What not to touch silently + +- The 5-phase startup order in `VIGIL.ps1` (preflight → quick-add → Outlook sync → auto-start shortcut → WPF UI + tray). +- Outlook COM `Sort()` **before** `Restrict()` — flips break flagged-email counts. +- DPAPI wrap of `tasks.json` (CurrentUser scope, BitLocker-off branch). +- Atomic-write contract (`[System.IO.File]::Replace`, never `Move-Item -Force`). +- Single-instance `Global\VIGIL_TaskTracker` mutex + window reactivation P/Invoke. +- 500-line log rotation. +- Reduce-motion variant (strip Storyboards, do not re-introduce them). + +These are tested invariants — if you have to touch one, call it out in the PR body and add a regression test. + +## Reporting + +- Code-touching issues / progress → Paperclip thread on the parent issue. +- Security findings → [`SECURITY.md`](SECURITY.md) — never a public GitHub issue. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..94beda4 --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,146 @@ +# CLAUDE.md — Vigil + +> Architecture + conventions SSoT for code-touching changes on Vigil. Per-issue specifics live in the Paperclip thread; runbooks live in `shared/runbooks/` (currently inherited from the codeiq sibling project — see References). +> +> The rule of last resort: **`/home/dev/.claude/rules/*.md` wins**. This file does not contradict it; it specialises it for Vigil. + +--- + +## 1. What Vigil is + +Vigil is a **Windows-first personal task command center** — a single-file PowerShell + WPF desktop app that unifies Outlook flagged emails / calendar items / open tasks with a manual task list, behind a chromeless Fluent (Mica) WPF window. Single-user, MIT-licensed, no compiled binary distribution. + +The product target is one knowledge worker on their own machine. There is no SaaS surface, no shared backend, no public-internet attack surface. Distribution is the GitHub repo plus a local `pwsh -File .\VIGIL.ps1` invocation. + +## 2. Stack identification (RAN-55 prereq) + +| Layer | Choice | +|---|---| +| Primary language | **PowerShell 7.5+** (`pwsh`) — cross-platform core; `Test-Vigil.ps1` runs on Linux / macOS pwsh too | +| Legacy fallback | Windows PowerShell 5.1 — supported for the data layer; Fluent theme degrades | +| Runtime | **.NET 9** (PowerShell 7.5 is bundled on top of .NET 9) | +| UI | **WPF / Fluent / Mica** (Windows 11 visuals); guarded for Windows-only | +| Embedded C# | `Add-Type` inline P/Invoke for window reactivation + tray hotkeys | +| External integration | **Outlook COM** (15-minute sync); flagged emails / 24h calendar / open tasks | +| Storage | DPAPI-wrapped `tasks.json` (CurrentUser scope) when BitLocker is off | +| Tests | Pester-style asserts; `Test-Vigil.ps1` dot-sources VIGIL with `-NoUI` | +| Package manager | **None** — no `package-lock.json`, no `pom.xml`, no `requirements.txt`. Dependencies are framework-bundled (.NET / pwsh built-ins) | + +What this means for tooling: + +- **No language ecosystem dependency surface** to scan with OSV-Scanner / Dependabot package updaters. The supply-chain attack surface is GitHub Actions + the .NET / pwsh runtimes themselves. +- **The (B) OSS-CLI security stack is language-adapted** (see §4) — Semgrep keeps the secret-audit + GHA / YAML rules, OSV-Scanner runs as a no-op on the source tree (will turn into useful coverage if a `*.lock` is ever added), Trivy / Gitleaks / SBOM / jscpd are language-agnostic. +- **There is no compile / build step**. "CI" for Vigil is `pwsh -NoProfile -File ./Test-Vigil.ps1` plus the security workflow. + +## 3. Repository shape + +``` +VIGIL.ps1 — main app (≈99 KB). 5-phase startup: + preflight → quick-add popup → Outlook COM 15-min sync → + auto-start shortcut → WPF UI + tray. + Params: -NoUI, -IncludeCalendar. +preflight.ps1 — 60 environment checks (runtime, corp lockdown CLM / + AppLocker / AMSI, Azure AD, hardware). Emits a compact + bitmap `VIGIL:v1:::P:F:T`. +Test-Vigil.ps1 — dot-sources VIGIL with -NoUI; custom asserts; runs on + PS 5.1 and pwsh 6+. ≈116 cross-platform unit tests for + the data layer. +.vigil/ — runtime state (DPAPI-wrapped tasks.json, logs). + Colocated next to the script; fallback ~/.vigil; + legacy migration from the old userprofile path. +LICENSE — MIT (Amit Kumar). +README.md — user-facing run instructions + OpenSSF badge. +SECURITY.md — vulnerability disclosure policy. +AGENTS.md — agent collaborator entry-point. +.bestpractices.json — OpenSSF Best Practices self-assessment (project 12648). +.github/ — workflows (scorecard, security), Dependabot config. +``` + +## 4. Quality gates + +| Gate | Threshold | Where it runs | Failure action | +|---|---|---|---| +| Unit tests | All pass | `pwsh -NoProfile -File ./Test-Vigil.ps1` | Block merge | +| Signed commits | Every commit on `main` verifies | Branch protection + `gh api ... /commits/{sha}/check-runs` | Block merge | +| OpenSSF Scorecard | Best-effort; soft target ≥ 8.0/10. `Pinned-Dependencies` is the priority | `.github/workflows/scorecard.yml` (push to `main` + Mondays 06:00 UTC) | Surface in Security tab; do **not** gate merge | +| OpenSSF Best Practices | `passing` badge on https://www.bestpractices.dev/en/projects/12648 | bestpractices.dev admin UI | The hard gate per board. Tracked under [RAN-55](/RAN/issues/RAN-55) | +| OSS-CLI observability | Findings surfaced via SARIF + artifacts | `.github/workflows/security.yml` | Observation-only at bootstrap; promote to gate-blocking after a clean baseline | + +The OSS-CLI stack mirrors the codeiq sibling — Semgrep (SAST), OSV-Scanner (deps; mostly no-op for the PS tree), Trivy (filesystem CVEs + IaC misconfig on the GHA YAML), Gitleaks (secret scan over full history), jscpd (PowerShell duplication via tokenization), and `anchore/sbom-action` (SPDX SBOM via Syft). Cron: Mondays 06:00 UTC, same window as the Scorecard sweep. All third-party actions pinned by commit SHA. + +## 5. Code style + +- **PowerShell 7.5 first**. PS 5.1 compatibility is preserved for the data layer — no `?.` operator, no ternary, no pipeline `?` / `??` outside guarded blocks. Where a 7-only construct is justified, gate it with `if ($PSVersionTable.PSVersion.Major -ge 7)`. +- **Cross-platform core**. Anything that is not WPF / Outlook COM must run on Linux / macOS pwsh — the test suite enforces this. WPF and `System.Windows.*` types are loaded behind `if ($IsWindows)`. +- **`System.Drawing` is lazy-loaded**. Linux pwsh lacks libgdiplus; do not import at script top. +- **Atomic writes** via `[System.IO.File]::Replace`, never `Move-Item -Force`. +- **Outlook COM hygiene**: `Sort()` **before** `Restrict()` for correct flagged counts; reverse-order `ReleaseComObject` + forced GC after each session to prevent RCW leaks. +- **Single-instance**: `Global\VIGIL_TaskTracker` named mutex + P/Invoke window reactivation. Do not introduce a second process model. +- **Logs**: 500-line rotation. Don't rely on file growth being unbounded. +- **Reduce-motion** variant strips Storyboards; honour the user's preference. + +## 6. Branch / commit / PR rules + +- Branch off `main`. Conventional-commit subjects (`feat:`, `fix:`, `chore:`, `refactor:`, `test:`, `docs:`, `perf:`). +- One logical change per commit. Squash-merge into `main`. +- Every commit on `main` must be signed (ssh or GPG) — branch protection rejects unsigned commits. **Action item for the board:** enable "Require signed commits" + "Require pull request before merging" + "Require status checks" on `main` via repo Settings → Branches. +- PR title = conventional-commit subject. Body links the Paperclip issue (`Closes RAN-XX`), states "why" in 1–2 sentences, and notes any rollback considerations. +- No force-push to `main` ever. + +## 7. Security + +- **Inputs** — every Outlook field that hits the UI is treated as untrusted text; manual task input is escaped before being interpolated into XAML. +- **Path traversal** — task store path is canonicalized via `[System.IO.Path]::GetFullPath` and asserted to live under `.vigil/` or `~/.vigil`. +- **Secrets** — never in code, config, or commit history. The DPAPI key is per-user and never exfiltrated. CI secrets are repo-level only. +- **CVE policy** — High/Critical → block the merge; Medium → fix if a patched version exists, else document non-exploitability with TechLead sign-off; Low → tracked in the next bump cycle. +- **Vulnerability reporting** — see [`SECURITY.md`](SECURITY.md). Private disclosure only. +- **OSS-CLI observability stack** — `.github/workflows/security.yml` runs Semgrep / OSV-Scanner / Trivy / Gitleaks / jscpd / `anchore/sbom-action` on every PR + push to `main` + weekly cron. OpenSSF Scorecard runs in `.github/workflows/scorecard.yml`. + +## 8. Performance + +- Outlook COM sync is bounded to 15 minutes and runs on a separate runspace; never block the dispatcher thread. +- WPF binding updates batch through the dispatcher — no per-item invocations from inside a tight loop. +- Search input is debounced; the debounce is flushed on window close so the last text is never lost. +- 60 fps target for animations on Windows 11; Storyboards are removed entirely under `prefers-reduced-motion`-equivalent (custom flag). + +## 9. Build & distribution + +- **There is no build step.** Distribution is `git clone` + `pwsh .\VIGIL.ps1`. +- GitHub Actions are pinned by **commit SHA** in every workflow (Scorecard `Pinned-Dependencies`). +- No public-CDN runtime fetches, no auto-update phone-home, no telemetry default-on. +- No container image yet. If one is added, it must build from a minimal base (distroless / scratch / Alpine), pinned by digest, pushed to GHCR with provenance attestations. + +## 10. Supply-chain observability (OpenSSF) — RAN-55 + +| Surface | Status | +|---|---| +| OpenSSF Best Practices project page | https://www.bestpractices.dev/en/projects/12648 — `in_progress` → **target `passing`** (admin-UI flip is board-owned) | +| Best Practices self-assessment | [`.bestpractices.json`](.bestpractices.json) — `level: passing`, evidence pointers per category | +| Scorecard workflow | [`.github/workflows/scorecard.yml`](.github/workflows/scorecard.yml) — push to `main` + Mondays 06:00 UTC; SARIF → Security tab + artifact | +| OSS-CLI security workflow | [`.github/workflows/security.yml`](.github/workflows/security.yml) — Semgrep / OSV / Trivy / Gitleaks / jscpd / SBOM; PR + push + weekly cron | +| Dependabot | [`.github/dependabot.yml`](.github/dependabot.yml) — `github-actions` ecosystem only (no Maven / npm; Vigil has no package manager) | +| README badge | [![OpenSSF Best Practices](https://www.bestpractices.dev/projects/12648/badge)](https://www.bestpractices.dev/projects/12648) | + +### Scorecard baseline + target + +- **Baseline (first run after merge):** to be captured in the Security tab once the workflow lands. Comment with the snapshot here on first publish. +- **Stretch target:** **≥ 8.0 / 10** aggregate. Per the board, Scorecard is observational and does **not** gate merge — `passing` Best Practices is the only hard gate. +- **Priority checks:** `Pinned-Dependencies` (we already SHA-pin all actions), `Branch-Protection` (board to enable), `Token-Permissions` (workflows opt into the narrowest scopes), `Dangerous-Workflow` (no `pull_request_target` writes), `SAST` (Semgrep covers it). +- **Known low-scorers:** `Signed-Releases` is N/A until we ship a tagged release; `CII-Best-Practices` flips green once the bestpractices.dev project is at `passing`; `Webhooks` and `License` should already be green. + +## 11. Documentation + +- This file (`CLAUDE.md`) is the architecture + conventions SSoT. +- [`AGENTS.md`](AGENTS.md) is the entry-point for agent collaborators. +- [`SECURITY.md`](SECURITY.md) is the disclosure policy. +- [`.bestpractices.json`](.bestpractices.json) is the OpenSSF Best Practices self-assessment. + +## 12. References + +- `LICENSE` — MIT. +- `SECURITY.md` — disclosure policy. +- `.github/workflows/` — Scorecard + OSS-CLI security automations. +- `/home/dev/.claude/rules/*.md` — global engineering rules (parent SSoT). +- `RAN-50` — parent issue (OpenSSF rollout across the 5 paperclip projects). +- `RAN-55` — this issue (Vigil-specific landing). +- codeiq sibling (`/home/dev/projects/codeiq`) — `RAN-46` / `RAN-52` precedent. diff --git a/LICENSE b/LICENSE index 060d591..64be958 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ MIT License -Copyright (c) 2026 RandomCodeSpace +Copyright (c) 2026 Amit Kumar Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal diff --git a/README.md b/README.md index 9ffbfe1..f4a19bc 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,8 @@ # VIGIL +[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/12648/badge)](https://www.bestpractices.dev/projects/12648) +[![OpenSSF Scorecard](https://api.scorecard.dev/projects/github.com/RandomCodeSpace/vigil/badge)](https://scorecard.dev/viewer/?uri=github.com/RandomCodeSpace/vigil) + Personal task command center for Windows. Single-file PowerShell + WPF app with a chromeless Fluent window, Outlook sync, and a system tray icon. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..070148e --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,79 @@ +# Security Policy + +## Supported versions + +Vigil is distributed as PowerShell source, not a versioned binary. Security fixes land on `main` and are tagged when material — there is no formal LTS line. + +| Tracking | Status | +|---|---| +| `main` | Supported (current) | +| Older tagged commits | Best-effort; rebase onto `main` for fixes | + +If you are running Vigil from a clone, `git pull` on `main` is the patch channel. + +## Reporting a vulnerability + +Please **do not open a public GitHub issue** for security problems. + +Use one of: + +- **GitHub private vulnerability report** — preferred. Open `https://github.com/RandomCodeSpace/vigil/security/advisories/new` (you must be signed in to GitHub). The advisory channel is monitored by the maintainer. +- **Email** — `ak.nitrr13@gmail.com`. Put `[vigil security]` in the subject so the report is triaged ahead of normal mail. + +Please include: + +- The Vigil commit SHA (`git rev-parse HEAD`) or the line of the script affected. +- The PowerShell host + version (`$PSVersionTable | Out-String`). +- The shortest reproducer you can produce — the `pwsh -File` invocation plus any test input. +- Your assessment of impact (e.g., DPAPI key exposure, COM hijack, path traversal in the task store, info-disclosure via logs). +- Whether the issue is in Vigil's code or in a runtime / framework dependency (.NET, pwsh, Outlook COM), and the upstream advisory ID if known. + +## What you can expect + +- **Acknowledgement** within 72 hours. +- **Initial triage** within 7 days, with a severity rating (CVSS v3.1) and an indicative remediation timeline. +- **Coordinated disclosure** — we will agree on a public-disclosure date with the reporter; default is 90 days from triage, sooner for low-impact / already-public issues. +- **Credit** in the GHSA advisory and the README changelog (unless the reporter requests anonymity). + +There is no paid bug bounty. + +## Scope + +In-scope: + +- The `VIGIL.ps1`, `preflight.ps1`, and `Test-Vigil.ps1` scripts. +- The DPAPI-wrapped task store layout under `.vigil/` (key handling, atomic write contract, path-traversal hardening). +- The Outlook COM integration (RCW lifecycle, sort-before-restrict invariant, sync window bounding). +- The auto-start shortcut + tray icon flows (privilege escalation, hijack via writable shortcut paths). +- The single-instance mutex (`Global\VIGIL_TaskTracker`) and the P/Invoke window-reactivation surface. + +Out of scope: + +- Vulnerabilities that require pre-existing local code execution on the user's machine. Vigil is a single-user desktop tool — by definition you trust the code you run as yourself. +- Public-internet attack surface — Vigil does not bind a network socket and does not phone home. Deploying it behind hostile reverse proxies is out of scope because that deployment shape is unsupported. +- Findings in third-party services we do not control (Microsoft Outlook, Windows DPAPI, GitHub itself) — please report those upstream. +- Constrained Language Mode / AppLocker / AMSI-EDR interactions where the corporate policy is intentionally blocking script execution. `preflight.ps1` reports those as known blockers. + +## Hardening references + +- [`CLAUDE.md`](CLAUDE.md) §7 "Security" and §10 "Supply-chain observability" — CVE policy + OSS-CLI stack. +- [`.github/workflows/scorecard.yml`](.github/workflows/scorecard.yml) — OpenSSF Scorecard supply-chain checks. +- [`.github/workflows/security.yml`](.github/workflows/security.yml) — Semgrep / OSV-Scanner / Trivy / Gitleaks / jscpd / SBOM. +- [`.github/dependabot.yml`](.github/dependabot.yml) — automated GitHub Actions bumps. +- GitHub repo settings — secret scanning + push protection are expected to be **enabled** on the repo (board-owned action item if not yet). + +## Branch protection (board action item) + +Per [`CLAUDE.md`](CLAUDE.md) §6, `main` is expected to require: + +- Signed commits +- Pull request before merging +- Status checks (Scorecard + security workflow + Test-Vigil) to pass +- Linear history (squash merges only) +- Force-push and deletion blocked + +These are GitHub repo Settings → Branches and not enforceable from a workflow file. Tracked alongside [RAN-55](https://github.com/RandomCodeSpace/vigil/issues) until the toggles are flipped. + +## Changelog + +This file is versioned as part of the repo. Material changes (e.g., changing the disclosure timeline, raising the supported-versions table) are announced via a Release note when a tag is cut and a Paperclip board comment.