diff --git a/.bestpractices.json b/.bestpractices.json index 1768153c9..8fa3b0e43 100644 --- a/.bestpractices.json +++ b/.bestpractices.json @@ -16,11 +16,11 @@ "interact_justification": "README.md provides Install (clone + dot-source), Usage (CLI invocation + hotkeys), and Tests sections covering download, use, and contribution paths. Issue tracker at https://github.com/RandomCodeSpace/snipIT/issues is linked from the GitHub repo header.", "contribution_status": "Met", - "contribution_justification": "CONTRIBUTING.md at repo root is the contribution-process entry point: reporting (GitHub Issues for bugs, SECURITY.md for vulnerabilities), development workflow (fork → topic branch → Conventional Commits → signed commits via scripts/setup-git-signed.sh → PR → auto-merge on green CI), CI gate matrix with local commands, coding standards, reviewer expectations, documentation expectations. CONTRIBUTING.md delegates the full quality bar to shared/runbooks/engineering-standards.md (PowerShell variant of the company-canonical runbook).", + "contribution_justification": "CONTRIBUTING.md at repo root is the contribution-process entry point: reporting (GitHub Issues for bugs, SECURITY.md for vulnerabilities), development workflow (fork → topic branch → Conventional Commits → signed commits via scripts/setup-git-signed.sh → PR → auto-merge on green CI), CI gate matrix with local commands, coding standards, reviewer expectations, documentation expectations. CONTRIBUTING.md also carries the full quality bar: coding standards, branch / commit / PR rules, and the CI gate policy.", "contribution_url": "https://github.com/RandomCodeSpace/snipIT/blob/main/CONTRIBUTING.md", "contribution_requirements_status": "Met", - "contribution_requirements_justification": "CONTRIBUTING.md at repo root documents acceptable contributions: §What every PR must pass tabulates the 8 CI gates (headless tests, Windows AST parse, PSScriptAnalyzer Error-severity 0, Trivy HIGH/CRITICAL 0, Semgrep ERROR 0, Gitleaks 0, jscpd <3%, SBOM artifact) with the local commands to run each. §Coding standards covers the load-bearing rules (PowerShell 7.5+ only, Verb-Noun PascalCase, [CmdletBinding()] + param() for >1-arg functions, pure-logic functions in Core region for headless coverage, named-closure event-handler pattern, single-file deliverable invariant). The full quality bar — branch / commit / PR rules, security tooling, performance targets — is the contents of shared/runbooks/engineering-standards.md, which CONTRIBUTING.md links as the SSoT.", + "contribution_requirements_justification": "CONTRIBUTING.md at repo root documents acceptable contributions: §What every PR must pass tabulates the 8 CI gates (headless tests, Windows AST parse, PSScriptAnalyzer Error-severity 0, Trivy HIGH/CRITICAL 0, Semgrep ERROR 0, Gitleaks 0, jscpd <3%, SBOM artifact) with the local commands to run each. §Coding standards covers the load-bearing rules (PowerShell 7.5+ only, Verb-Noun PascalCase, [CmdletBinding()] + param() for >1-arg functions, pure-logic functions in Core region for headless coverage, named-closure event-handler pattern, single-file deliverable invariant). The full quality bar — branch / commit / PR rules, security tooling, performance targets — is documented in CONTRIBUTING.md itself, which is the single source of truth for what is acceptable in this repo.", "contribution_requirements_url": "https://github.com/RandomCodeSpace/snipIT/blob/main/CONTRIBUTING.md", "floss_license_status": "Met", @@ -34,7 +34,7 @@ "license_location_url": "https://github.com/RandomCodeSpace/snipIT/blob/main/LICENSE", "documentation_basics_status": "Met", - "documentation_basics_justification": "README.md at repo root IS the basic documentation for the software: §Features (capture, preview window, annotations, output, system integration), §Hotkeys (global + preview window), §Install (3-step clone + run, no admin, what first-launch does), §Usage (annotation flow, zoom, copy/save, new snip), §Architecture (single-file region layout + 10 pure Core functions + preview-window internals), §Tests (84 headless + 42 interactive), §Project files. Long-form material (design mocks, ADR-style notes) lives under docs/ with docs/README.md as the index pointing back to README/CLAUDE/SECURITY/engineering-standards/CHANGELOG. CLAUDE.md provides the agent/developer brief with build/test/run, conventions, gotchas, and the OpenSSF Scorecard baseline + target.", + "documentation_basics_justification": "README.md at repo root IS the basic documentation for the software and is the documentation entry point: §Why snipIT (capture, annotation editor, theming, single-file zero-dependency deliverable), §Quick start (3-step clone + run, no admin, what first launch does, plus the global and editor hotkey table), §Building from source (authoritative src/ and xaml/ sources, the generated distribution rule, the build command, and the three test entry points), §Contributing, §License. README.md links onward to CONTRIBUTING.md, which provides the developer brief: development workflow, the 8-gate CI matrix with local commands, and coding standards.", "documentation_basics_url": "https://github.com/RandomCodeSpace/snipIT/blob/main/README.md", "documentation_interface_status": "Met", @@ -44,10 +44,10 @@ "sites_https_justification": "Project, repo, and download endpoints all served over HTTPS. Project page https://www.bestpractices.dev/en/projects/12647, repo https://github.com/RandomCodeSpace/snipIT, and `git clone` URL https://github.com/RandomCodeSpace/snipIT.git all use TLS.", "discussion_status": "Met", - "discussion_justification": "GitHub Issues at https://github.com/RandomCodeSpace/snipIT/issues — public, threaded, supports cross-references. Used as the bug-report and enhancement-discussion channel per shared/runbooks/engineering-standards.md.", + "discussion_justification": "GitHub Issues at https://github.com/RandomCodeSpace/snipIT/issues — public, threaded, supports cross-references. Used as the bug-report and enhancement-discussion channel per CONTRIBUTING.md.", "english_status": "Met", - "english_justification": "All project documentation (README.md, SECURITY.md, CLAUDE.md, shared/runbooks/engineering-standards.md), code comments in SnipIT.ps1, and commit/PR history are written in English. Issue and PR responses are in English.", + "english_justification": "All project documentation (README.md, CONTRIBUTING.md, SECURITY.md, CHANGELOG.md), code comments in SnipIT.ps1, and commit/PR history are written in English. Issue and PR responses are in English.", "maintained_status": "Met", "maintained_justification": "Project is actively maintained — recent commits include the OpenSSF baseline work (the OpenSSF Best Practices + Scorecard bootstrap, PR #1) and feature/bug fixes such as capture-target exclusion. Repo is not archived, is not marked DEPRECATED, and has no no-maintenance-intended badge. Maintainer (Amit Kumar) responds in the issue tracker.", @@ -59,7 +59,7 @@ "repo_track_justification": "Tracked in git (the canonical FLOSS distributed version-control system). All files under .git/ at repo root.", "repo_interim_status": "Met", - "repo_interim_justification": "All interim development is committed to the public repo's main branch — no out-of-band private branches gate-keep work. Squash-merge is the only allowed merge style (engineering-standards.md §3); intermediate work-in-progress is visible in the PR thread before squash.", + "repo_interim_justification": "All interim development is committed to the public repo's main branch — no out-of-band private branches gate-keep work. Squash-merge is the only allowed merge style (documented in CONTRIBUTING.md); intermediate work-in-progress is visible in the PR thread before squash.", "repo_distributed_status": "Met", "repo_distributed_justification": "git is a fully distributed VCS (each clone contains the full history and every operation works offline). Repo at https://github.com/RandomCodeSpace/snipIT is git-native.", @@ -73,7 +73,7 @@ "version_semver_url": "https://github.com/RandomCodeSpace/snipIT/releases/tag/v0.1.0", "version_tags_status": "Met", - "version_tags_justification": "CHANGELOG.md states 'Version numbers below correspond to git tags on main.' First release is the annotated, SSH-signed git tag `v0.1.0` (https://github.com/RandomCodeSpace/snipIT/releases/tag/v0.1.0), cut from the `release: cut snipIT v0.1.0` PR squash commit. The signed-tag requirement is codified in shared/runbooks/engineering-standards.md §8 ('Commit identity and signed commits'): `tag.gpgsign=true` is set repo-locally by scripts/setup-git-signed.sh; branch protection on main enforces verified signatures.", + "version_tags_justification": "CHANGELOG.md states 'Version numbers below correspond to git tags on main.' First release is the annotated, SSH-signed git tag `v0.1.0` (https://github.com/RandomCodeSpace/snipIT/releases/tag/v0.1.0), cut from the `release: cut snipIT v0.1.0` PR squash commit. The signed-tag requirement is codified in CONTRIBUTING.md (§Development workflow, signed commits): `tag.gpgsign=true` is set repo-locally by scripts/setup-git-signed.sh; branch protection on main enforces verified signatures.", "version_tags_url": "https://github.com/RandomCodeSpace/snipIT/releases/tag/v0.1.0", "release_notes_status": "Met", @@ -92,7 +92,7 @@ "report_tracker_justification": "GitHub Issues at https://github.com/RandomCodeSpace/snipIT/issues serves as the public, threaded, searchable issue tracker for bug reports and enhancement requests.", "report_responses_status": "Met", - "report_responses_justification": "Maintainer (Amit Kumar) actively triages and responds to issues — see issue/PR history on https://github.com/RandomCodeSpace/snipIT. PRs are reviewed before squash-merge per engineering-standards.md §3.", + "report_responses_justification": "Maintainer (Amit Kumar) actively triages and responds to issues — see issue/PR history on https://github.com/RandomCodeSpace/snipIT. PRs are reviewed before squash-merge per CONTRIBUTING.md.", "enhancement_responses_status": "Met", "enhancement_responses_justification": "Enhancement requests are tracked in GitHub Issues alongside bugs and triaged in the same loop — active feature work is tracked in GitHub Issues.", @@ -125,23 +125,23 @@ "test_justification": "Test-SnipIT.ps1 — headless test suite covering rectangle math, click-vs-drag thresholding, loupe clamping for negative-origin multi-monitor setups, filename + image-format derivation, capture-rect validation, install-path computation, and shortcut argument formatting. Test-SnipIT-Interactive.ps1 covers preview-window + capture flows interactively. Headless tier gated in CI per .github/workflows/test.yml on Linux + Windows runners.", "test_invocation_status": "Met", - "test_invocation_justification": "Headless tests run via `pwsh -NoProfile -File ./Test-SnipIT.ps1`. CI invocation lives in .github/workflows/test.yml (`test` job, Linux + Windows matrix). Documented in CLAUDE.md §Build / test / run.", + "test_invocation_justification": "Headless tests run via `pwsh -NoProfile -File ./Test-SnipIT.ps1`. CI invocation lives in .github/workflows/test.yml (`test` job, Linux + Windows matrix). Documented in README.md §Building from source and in CONTRIBUTING.md.", "test_most_status": "Met", - "test_most_justification": "126 tests across two suites cover the production surface breadth-completely: (1) Test-SnipIT.ps1 — 84 headless unit tests over the 10 pure functions exported by the Core region (Get-DragRectangle, Test-IsClickVsDrag, Get-LoupeSourceRect, Get-LoupePosition, Get-DefaultSnipFilename, Get-ImageFormatNameFromPath, Test-CaptureRectValid, Get-CropBounds, Get-InstallPaths, Get-ShortcutArguments) — every code branch in each function exercised, including edge cases (negative-origin multi-monitor, DPI-aware crop bounds, MinSize boundary, dot-prefixed hidden filenames, uppercase extensions). (2) Test-SnipIT-Interactive.ps1 — 42 WPF integration tests over the preview-window's named closures (pan, zoom 5%–1000%, drawing tools highlight/rect/arrow/text, six-color palette, undo/redo, hit-test topmost-wins, full HandleMouseDown dispatch, text-tool live-color editing, flattening). Line-coverage percentage is not measured today (no Coveralls/Codecov integration); coverage is judged by branch+behaviour breadth per shared/runbooks/engineering-standards.md §4.", + "test_most_justification": "126 tests across two suites cover the production surface breadth-completely: (1) Test-SnipIT.ps1 — 84 headless unit tests over the 10 pure functions exported by the Core region (Get-DragRectangle, Test-IsClickVsDrag, Get-LoupeSourceRect, Get-LoupePosition, Get-DefaultSnipFilename, Get-ImageFormatNameFromPath, Test-CaptureRectValid, Get-CropBounds, Get-InstallPaths, Get-ShortcutArguments) — every code branch in each function exercised, including edge cases (negative-origin multi-monitor, DPI-aware crop bounds, MinSize boundary, dot-prefixed hidden filenames, uppercase extensions). (2) Test-SnipIT-Interactive.ps1 — 42 WPF integration tests over the preview-window's named closures (pan, zoom 5%–1000%, drawing tools highlight/rect/arrow/text, six-color palette, undo/redo, hit-test topmost-wins, full HandleMouseDown dispatch, text-tool live-color editing, flattening). Line-coverage percentage is not measured today (no Coveralls/Codecov integration); coverage is judged by branch+behaviour breadth per the testing policy in CONTRIBUTING.md.", "test_most_url": "https://github.com/RandomCodeSpace/snipIT/blob/main/Test-SnipIT.ps1", "test_continuous_integration_status": "Met", "test_continuous_integration_justification": "GitHub Actions runs the headless test suite on every push and pull request to main per .github/workflows/test.yml — see https://github.com/RandomCodeSpace/snipIT/actions/workflows/test.yml.", "test_policy_status": "Met", - "test_policy_justification": "shared/runbooks/engineering-standards.md §4 (Testing tiers) codifies the policy: 'New behaviour ships with at least one headless test where the logic is testable without a desktop session. UI-only paths are documented in README.md under Tests.' Enforced via PR review per §3.", + "test_policy_justification": "CONTRIBUTING.md §Coding standards codifies the policy: new behaviour ships with at least one test where the logic is testable without a desktop session, and UI-only paths are called out in the PR. Enforced via PR review before squash-merge.", "tests_are_added_status": "Met", "tests_are_added_justification": "Commit history shows test additions accompanying feature work — Test-SnipIT.ps1 covers seven functional areas (rectangle math, click-vs-drag thresholding, loupe clamping, filename derivation, capture-rect validation, install-path, shortcut argument formatting). Engineering-standards.md §4 requires it for new behaviour.", "tests_documented_added_status": "Met", - "tests_documented_added_justification": "shared/runbooks/engineering-standards.md §4 documents the test-with-new-behaviour policy for contributors. README.md §Tests describes the headless vs. interactive tiers.", + "tests_documented_added_justification": "CONTRIBUTING.md documents the test-with-new-behaviour policy for contributors. README.md §Building from source lists the headless and interactive test entry points.", "warnings_status": "Met", "warnings_justification": "PSScriptAnalyzer is the PowerShell-equivalent of compiler warnings — invoked at Error severity in .github/workflows/security.yml (`psscriptanalyzer` job) against SnipIT.ps1. Warnings (non-Error severity) are surfaced in the same job's 'Surface warnings (non-blocking)' step, grouped by RuleName for visibility.", @@ -153,7 +153,7 @@ "warnings_strict_justification": "PSScriptAnalyzer at Error severity is the strictest standard gate available for PowerShell linting — it catches the highest-impact rules from the analyzer rule set (CmdletAliases, AvoidUsingPlainTextForPassword, AvoidUsingInvokeExpression, etc.). Engineering-standards.md §1 mandates zero Error-severity findings as a hard gate.", "know_secure_design_status": "Met", - "know_secure_design_justification": "snipIT applies least-privilege principles documented in shared/runbooks/engineering-standards.md §5.2 (Code hygiene): every P/Invoke `Add-Type` block (user32.dll / gdi32.dll / kernel32.dll) is reviewed for input-handle validation; user-supplied save paths go through `Resolve-Path` + canonical-form check before write; runs without admin elevation; no network IO outside clipboard. SECURITY.md §Scope explicitly enumerates the trust boundary (user-controlled HWNDs, file-save paths, clipboard, hotkey registration) and threat classes (LPE, info-disclosure, arbitrary file write, DoS).", + "know_secure_design_justification": "snipIT applies least-privilege principles documented in CONTRIBUTING.md (§Coding standards, code hygiene): every P/Invoke `Add-Type` block (user32.dll / gdi32.dll / kernel32.dll) is reviewed for input-handle validation; user-supplied save paths go through `Resolve-Path` + canonical-form check before write; runs without admin elevation; no network IO outside clipboard. SECURITY.md §Scope explicitly enumerates the trust boundary (user-controlled HWNDs, file-save paths, clipboard, hotkey registration) and threat classes (LPE, info-disclosure, arbitrary file write, DoS).", "know_common_errors_status": "Met", "know_common_errors_justification": "Engineering-standards.md §5.1 mandates Semgrep with `p/owasp-top-ten` and `p/security-audit` packs (covering OWASP Top 10 + common SAST patterns including path traversal, dangerous deserialization, command injection) — gated at Error severity in .github/workflows/security.yml. PSScriptAnalyzer covers PowerShell-specific common errors (Invoke-Expression abuse, plain-text passwords, etc.). CVE policy in §5.2 enumerates High/Critical → block, Medium → fix or document non-exploitability.", @@ -186,7 +186,7 @@ "crypto_random_justification": "snipIT does not require cryptographically-secure randomness — see crypto_published_justification.", "delivery_mitm_status": "Met", - "delivery_mitm_justification": "Source delivery is via `git clone https://github.com/RandomCodeSpace/snipIT.git` over TLS. GitHub serves repository contents over HTTPS; `git clone` over HTTPS verifies GitHub's TLS certificate. Signed commits (engineering-standards.md §1, scripts/setup-git-signed.sh — branch protection on main requires verified signatures) provide additional integrity over the TLS channel.", + "delivery_mitm_justification": "Source delivery is via `git clone https://github.com/RandomCodeSpace/snipIT.git` over TLS. GitHub serves repository contents over HTTPS; `git clone` over HTTPS verifies GitHub's TLS certificate. Signed commits (CONTRIBUTING.md, scripts/setup-git-signed.sh — branch protection on main requires verified signatures) provide additional integrity over the TLS channel.", "delivery_unsigned_status": "Met", "delivery_unsigned_justification": "All commits on main are GPG/SSH-signed and verified by GitHub — branch protection on main requires `Require signed commits`. scripts/setup-git-signed.sh applies the repo-local git config for contributors (supports ssh-format and openpgp-format signing). Engineering-standards.md §1 lists 'Signed commits — every commit on main must verify' as a hard gate.", @@ -195,19 +195,19 @@ "vulnerabilities_fixed_60_days_justification": "No publicly-known vulnerabilities to date. SECURITY.md §What you can expect publishes the SLA: acknowledgement 72h, triage 7d, coordinated disclosure default 90 days from triage. Trivy filesystem scan and Dependabot security updates monitor for new CVEs continuously per .github/workflows/security.yml and .github/dependabot.yml.", "vulnerabilities_critical_fixed_status": "Met", - "vulnerabilities_critical_fixed_justification": "No critical vulnerabilities to date. Trivy filesystem scan in .github/workflows/security.yml gates HIGH and CRITICAL severity at exit-code 1 (block merge). CVE policy in shared/runbooks/engineering-standards.md §5.2: High/Critical → block immediately.", + "vulnerabilities_critical_fixed_justification": "No critical vulnerabilities to date. Trivy filesystem scan in .github/workflows/security.yml gates HIGH and CRITICAL severity at exit-code 1 (block merge). CVE policy in CONTRIBUTING.md: High/Critical → block immediately.", "no_leaked_credentials_status": "Met", "no_leaked_credentials_justification": "Gitleaks runs full git-history secret scan in .github/workflows/security.yml (`gitleaks` job, `fetch-depth: 0`) — gated at zero findings (block merge). GitHub repo-level secret scanning + push protection are enabled at repo Settings → Code security. Engineering-standards.md §5.2 mandates 'Secrets — never in code, config, or commit history.'", "static_analysis_status": "Met", - "static_analysis_justification": "Two SAST gates in .github/workflows/security.yml: (1) Semgrep with `p/security-audit` and `p/owasp-top-ten` packs at Error severity — language-agnostic gate covering OWASP Top 10 + common SAST patterns (path traversal, dangerous deserialization, command injection); (2) PSScriptAnalyzer at Error severity — PowerShell-specific lint (CmdletAliases, AvoidUsingInvokeExpression, AvoidUsingPlainTextForPassword, etc.). No first-party Semgrep p/powershell pack ships in the registry today, so PSScriptAnalyzer is the language-specific channel — codeiq-equivalent of `p/java`. Both gate merge per engineering-standards.md §1. CodeQL is intentionally excluded — no PowerShell pack today; Semgrep + PSScriptAnalyzer cover the surface (per shared/runbooks/engineering-standards.md §5.1).", + "static_analysis_justification": "Two SAST gates in .github/workflows/security.yml: (1) Semgrep with `p/security-audit` and `p/owasp-top-ten` packs at Error severity — language-agnostic gate covering OWASP Top 10 + common SAST patterns (path traversal, dangerous deserialization, command injection); (2) PSScriptAnalyzer at Error severity — PowerShell-specific lint (CmdletAliases, AvoidUsingInvokeExpression, AvoidUsingPlainTextForPassword, etc.). No first-party Semgrep p/powershell pack ships in the registry today, so PSScriptAnalyzer is the language-specific channel — codeiq-equivalent of `p/java`. Both gate merge per CONTRIBUTING.md. CodeQL is intentionally excluded — no PowerShell pack today; Semgrep + PSScriptAnalyzer cover the surface (per CONTRIBUTING.md).", "static_analysis_common_vulnerabilities_status": "Met", "static_analysis_common_vulnerabilities_justification": "Semgrep `p/owasp-top-ten` pack (in .github/workflows/security.yml) explicitly targets the OWASP Top 10 vulnerability categories. `p/security-audit` adds path traversal, dangerous deserialization, and command injection patterns. Both run at Error severity gating merge.", "static_analysis_fixed_status": "Met", - "static_analysis_fixed_justification": "All four SAST/lint signals (Semgrep, PSScriptAnalyzer, Trivy, jscpd) gate merge at zero Error-severity / zero High-Critical findings per engineering-standards.md §1. Findings cannot accumulate — they are fixed in the same PR or the merge is blocked.", + "static_analysis_fixed_justification": "All four SAST/lint signals (Semgrep, PSScriptAnalyzer, Trivy, jscpd) gate merge at zero Error-severity / zero High-Critical findings per CONTRIBUTING.md. Findings cannot accumulate — they are fixed in the same PR or the merge is blocked.", "static_analysis_often_status": "Met", "static_analysis_often_justification": "Static analysis runs on every push to main and every pull request via .github/workflows/security.yml — fail-fast off so all signals (Semgrep, PSScriptAnalyzer, Trivy, Gitleaks, jscpd, SBOM) surface on a single run. No commit reaches main without a clean pass.", @@ -217,12 +217,12 @@ "dynamic_analysis_url": "https://github.com/RandomCodeSpace/snipIT/blob/main/Test-SnipIT-Interactive.ps1", "dynamic_analysis_unsafe_status": "N/A", - "dynamic_analysis_unsafe_justification": "PowerShell on .NET is a memory-safe / type-safe runtime (managed CLR, no manual memory management) — the criterion's targets (valgrind, ASAN, MSAN) are designed for unmanaged C/C++ codebases and do not apply. The P/Invoke surface against user32.dll / gdi32.dll is reviewed manually per engineering-standards.md §5.2.", + "dynamic_analysis_unsafe_justification": "PowerShell on .NET is a memory-safe / type-safe runtime (managed CLR, no manual memory management) — the criterion's targets (valgrind, ASAN, MSAN) are designed for unmanaged C/C++ codebases and do not apply. The P/Invoke surface against user32.dll / gdi32.dll is reviewed manually per CONTRIBUTING.md.", "dynamic_analysis_enable_assertions_status": "Met", "dynamic_analysis_enable_assertions_justification": "Test-SnipIT-Interactive.ps1 line 11 enables both PowerShell assertion modes for the entire dynamic-analysis run: `Set-StrictMode -Version Latest` (rejects access to undefined variables, missing object properties, function calls with extra arguments — the PowerShell equivalent of compiled-language assertion mode) and `$ErrorActionPreference = 'Stop'` (turns every non-terminating error into a terminating exception, so any failed precondition aborts the test rather than silently returning $null). Production runs of SnipIT.ps1 deliberately do *not* enable strict-mode globally — these assertion-equivalents are scoped to dynamic analysis only, per the criterion's guidance that 'these assertions should not be enabled in production builds.'", "dynamic_analysis_enable_assertions_url": "https://github.com/RandomCodeSpace/snipIT/blob/main/Test-SnipIT-Interactive.ps1", "dynamic_analysis_fixed_status": "N/A", - "dynamic_analysis_fixed_justification": "No dynamic analysis tool is integrated — see dynamic_analysis_justification. When a tool is added, findings will be gated per the same hard-gate model as the static-analysis signals (engineering-standards.md §1)." + "dynamic_analysis_fixed_justification": "No dynamic analysis tool is integrated — see dynamic_analysis_justification. When a tool is added, findings will be gated per the same hard-gate model as the static-analysis signals (CONTRIBUTING.md)." } diff --git a/.github/workflows/security.yml b/.github/workflows/security.yml index 9f49aad8d..884ff678e 100644 --- a/.github/workflows/security.yml +++ b/.github/workflows/security.yml @@ -18,8 +18,8 @@ name: Security (OSS-CLI) # is PSScriptAnalyzer (added below) — codeiq-equivalent of `p/java`. # - jscpd format set to `powershell`, with generated release and authoritative # development sources scanned separately to exclude intentional parity. -# - Added `psscriptanalyzer` job — language lint per -# `shared/runbooks/engineering-standards.md` (PowerShell variant). +# - Added `psscriptanalyzer` job — language lint per the coding standards +# in `CONTRIBUTING.md`. on: push: branches: [main] diff --git a/AGENTS.md b/AGENTS.md deleted file mode 100644 index 46eee6f18..000000000 --- a/AGENTS.md +++ /dev/null @@ -1,118 +0,0 @@ -# snipIT — Agent brief - -Read this at session start. It is the standing context for any agent touching this repo. - -## What it is - -A **professional snipping tool** for Windows 11 written in **pure PowerShell -7.5+** on **.NET 9**. Smart hover-to-highlight capture, magnifier loupe, -floating widget, system tray, chromeless WPF Fluent preview, and a full -annotation editor — zero external runtime dependencies and no admin elevation. - -**Board reversal (accepted 2026-07-12):** modular `src/` PowerShell and -external `xaml/` files are now the authoritative development source. -`SnipIT.ps1` remains the headline single-file distribution and is generated -deterministically. Never edit `SnipIT.ps1` directly. - -## Repo layout - -```text -src/ -├── 00-Core.ps1 pure cross-platform logic and -CoreOnly boundary -├── 10-Bootstrap.ps1 startup, settings, install, XAML loader -├── 20-Native.ps1 Win32 interop and native window services -├── 30-Capture.ps1 capture coordinator, bitmaps, overlays -├── 40-Preview.ps1 preview and annotation editor -├── 50-Tray.ps1 tray, settings/about windows, floating widget -└── 90-Main.ps1 application entry point and cleanup -xaml/ six authoritative WPF surfaces/resources -Build-SnipIT.ps1 sole manifest/order authority and release generator -SnipIT.Dev.ps1 repository development launcher -SnipIT.ps1 generated checked-in standalone distribution -Test-SnipIT-Build.ps1 deterministic-build and failure fixtures -Test-SnipIT.ps1 pure-logic tests (Linux + Windows, no Pester) -Test-SnipIT-Interactive.ps1 WPF integration tests (Windows only) -scripts/Export-SnipITModules.ps1 retained AST/provenance round-trip tool -README.md install, usage, architecture, contributor workflow -SECURITY.md disclosure policy and scope -shared/runbooks/engineering-standards.md PowerShell engineering runbook -``` - -The generated `SnipIT.ps1` must stay portable: no runtime lookup of `src/`, -`xaml/`, the builder, repository paths, external modules, or network resources. - -## Build / test / run - -| Action | Command | -|---|---| -| Run the distribution | `pwsh -Sta -File ./SnipIT.ps1` | -| Run development sources | `pwsh -Sta -File ./SnipIT.Dev.ps1` | -| Regenerate distribution | `pwsh -NoProfile -File ./Build-SnipIT.ps1` | -| Reject stale distribution | `git diff --exit-code -- SnipIT.ps1` | -| Build contract tests | `pwsh -NoProfile -File ./Test-SnipIT-Build.ps1` | -| Release pure tests | `pwsh -NoProfile -File ./Test-SnipIT.ps1` | -| Development pure tests | `$env:SNIPIT_SCRIPT_UNDER_TEST='./SnipIT.Dev.ps1'; pwsh -NoProfile -File ./Test-SnipIT.ps1` | -| Release WPF tests | `pwsh -NoProfile -Sta -File ./Test-SnipIT-Interactive.ps1` | -| Development WPF smoke | `$env:SNIPIT_SCRIPT_UNDER_TEST='./SnipIT.Dev.ps1'; $env:SNIPIT_TEST_GROUP='Floating Studio preview shell'; pwsh -NoProfile -Sta -File ./Test-SnipIT-Interactive.ps1` | - -Always regenerate after changing `src/` or `xaml/`. Commit the source change and -generated release together. CI rebuilds and rejects any stale `SnipIT.ps1`. - -## Conventions - -- **PowerShell 7.5+ only.** No PowerShell 5.1 fallbacks. -- Functions use approved `Verb-Noun` PascalCase names. Use `[CmdletBinding()]` - and `param()` for anything with more than one argument. -- Pure helpers belong in `src/00-Core.ps1`; `-CoreOnly` must remain usable on - Linux without loading WPF, WinForms, or other Windows-only assemblies. -- The builder is the only module/XAML order authority. Generated provenance - uses manifest-relative forward-slash paths and never absolute paths. -- Preview mouse handlers are named closures captured by `New-SnipPreviewWindow`; - real WPF handlers remain one-line wrappers. Tests drive these closures through - the `Show-PreviewWindow -TestAction` seam. -- `SNIPIT_SCRIPT_UNDER_TEST` redirects either test harness to the development - launcher. Keep injection step-scoped; release tests must remain release tests. -- `SNIPIT_TEST_MODE=1` suppresses mutex, install, tray, hotkeys, and the main - loop so either launch path can be dot-sourced without side effects. -- All commits on `main` are signed. Run `scripts/setup-git-signed.sh` once in a - fresh worktree; Task commits must use signing as required by the workflow. - -## Engineering standards - -The repo follows `shared/runbooks/engineering-standards.md`. - -- Merge gates: deterministic build plus stale-release diff, tests, AST parse, - **PSScriptAnalyzer Error**, **Trivy HIGH/CRITICAL**, **Semgrep ERROR**, - **Gitleaks**, **jscpd < 3%**, OpenSSF Best Practices `passing`, and signed commits. -- SBOM, OpenSSF Scorecard, and Dependabot are surfaces, not merge gates. -- **OSS-CLI only.** No Sonar, CodeQL, or NVD-direct tools. -- Every GitHub Action reference must remain pinned to a full commit SHA. - -OpenSSF Best Practices project: . -Scorecard workflow is observational; best-effort target is at least 8.0/10 and -material regressions create a security chore rather than blocking a PR. - -## Gotchas - -- **Capture loop ownership.** `Invoke-CaptureLoop` owns every captured bitmap. - Preview disposes it on close, and `CaptureFactory` creates a fresh bitmap per - iteration. Never dispose inside the factory or reuse a preallocated bitmap. -- **SnipIT-window exclusion.** Register every new top-level SnipIT window through - `Hide-OwnSnipITWindowsForCapture` so it is excluded from captured frames. -- **Per-monitor DPI is requested, not guaranteed.** Startup calls - `SetProcessDpiAwarenessContext(PER_MONITOR_AWARE_V2)` in `src/20-Native.ps1` - but discards the result. The call fails with `ERROR_ACCESS_DENIED` whenever - process DPI awareness was already set before the script ran — verified - 2026-08-13 under a host where injected software (Citrix App Protection) - pre-loads WinForms/WPF into every `pwsh`, leaving the process SYSTEM aware. - In that mode `GetDpiForMonitor` returns the system DPI for every monitor and - Windows virtualizes coordinates/captures on mixed-DPI setups. Capture math - still supports mixed scaling and negative virtual desktop origins; never - assume `(0,0)` is the virtual desktop top-left, and never assume the PMv2 - request succeeded. -- **Single instance.** A second launch notifies and exits unless - `SNIPIT_TEST_MODE=1` is set. -- **Generated-file ownership.** Do not patch `SnipIT.ps1`; change authoritative - source and run `Build-SnipIT.ps1`. -- **Pinned dependencies.** Never replace a full action SHA with a tag such as - `actions/checkout@v4`. diff --git a/CHANGELOG.md b/CHANGELOG.md index 715080670..4ff33b43f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -40,14 +40,14 @@ First tagged release. Establishes the OpenSSF Best Practices `passing` baseline - `.github/dependabot.yml` — weekly grouped GitHub Actions updates. - `SECURITY.md` — private vulnerability disclosure policy, supported versions, and scope. - `.bestpractices.json` — OpenSSF Best Practices self-assessment (project [12647](https://www.bestpractices.dev/en/projects/12647)). - - `CLAUDE.md` — agent / contributor brief: build, test, run, conventions, OpenSSF Scorecard baseline + target. - - `shared/runbooks/engineering-standards.md` — PowerShell variant of the company canonical engineering-standards runbook. + - Contributor brief covering build, test, run, conventions, and the OpenSSF Scorecard baseline + target. + - PowerShell engineering standards — quality gates, code style, and CVE policy. - `scripts/setup-git-signed.sh` — one-shot signed-commit setup (SSH / OpenPGP / x509). - Branch protection on `main` — required signed commits, linear history, force-push and deletion blocked, eight required CI status checks. - Repo-level Dependabot security updates enabled. - Canonical-schema rewrite of `.bestpractices.json` so the bestpractices.dev autofill robot can pre-fill the criteria page on board flip ([PR #3](https://github.com/RandomCodeSpace/snipIT/pull/3)). -- `CHANGELOG.md` (this file) and `docs/README.md` index — addresses the `release_notes` and `documentation_basics` gaps surfaced by the bestpractices.dev autofill audit ([PR #4](https://github.com/RandomCodeSpace/snipIT/pull/4) / [#5](https://github.com/RandomCodeSpace/snipIT/pull/5)). -- `CONTRIBUTING.md` at repo root — conventional contribution-process entry point: §Reporting (Issues + SECURITY.md), §Development workflow, §What every PR must pass (8-row CI gate matrix with local commands), §Coding standards delegating to `shared/runbooks/engineering-standards.md` ([PR #7](https://github.com/RandomCodeSpace/snipIT/pull/7)). +- `CHANGELOG.md` (this file) — addresses the `release_notes` and `documentation_basics` gaps surfaced by the bestpractices.dev autofill audit ([PR #4](https://github.com/RandomCodeSpace/snipIT/pull/4) / [#5](https://github.com/RandomCodeSpace/snipIT/pull/5)). +- `CONTRIBUTING.md` at repo root — conventional contribution-process entry point: §Reporting (Issues + SECURITY.md), §Development workflow, §What every PR must pass (8-row CI gate matrix with local commands), §Coding standards ([PR #7](https://github.com/RandomCodeSpace/snipIT/pull/7)). ### Changed - `.github/workflows/test.yml` — every action SHA-pinned (Scorecard `Pinned-Dependencies`); top-level `permissions: read-all`; PSScriptAnalyzer moved out into `security.yml` so the SAST/lint signals are co-located with the rest of the security stack. diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index 2102f2dc3..000000000 --- a/CLAUDE.md +++ /dev/null @@ -1,8 +0,0 @@ -# snipIT agent compatibility note - -The authoritative repository instructions are in [`AGENTS.md`](AGENTS.md). -Read that file before modifying this repository. It records the accepted -2026-07-12 board reversal to modular authoritative `src/` and `xaml/` sources, -the deterministic `Build-SnipIT.ps1` workflow, and the rule that generated -`SnipIT.ps1` must never be edited directly. `SnipIT.ps1` is the standalone -single-file distribution, while `src/` and `xaml/` are authoritative. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 6723b0d74..a66a38981 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -33,14 +33,15 @@ CI gates every PR on the following — please run them locally before requesting ## Coding standards (acceptable contributions) -The full quality bar — quality gates, code style, branch/commit/PR rules, security tooling, performance targets — is codified in [`shared/runbooks/engineering-standards.md`](shared/runbooks/engineering-standards.md), the PowerShell variant of the company-canonical runbook. Treat that file as the single source of truth for what is acceptable in this repo. The most load-bearing rules: +The quality bar for this repo, in short: every commit on `main` is signed (run `scripts/setup-git-signed.sh` once per worktree) and follows [Conventional Commits](https://www.conventionalcommits.org/); code is PowerShell 7.5+ in `Verb-Noun` style with no PS5.1 fallbacks; new behaviour ships with at least one test where the logic is testable without a desktop session, and UI-only paths are called out in the PR; and the eight CI gates in the table above are hard gates with zero tolerance — a finding is fixed in the same PR or the merge is blocked. The most load-bearing rules: - **PowerShell 7.5+ only.** No PS5.1 fallbacks, no `Add-Type` shims that only compile on Windows PowerShell. - **Functions: `Verb-Noun` PascalCase**, [approved verbs](https://learn.microsoft.com/powershell/scripting/developer/cmdlet/approved-verbs-for-windows-powershell-commands), `[CmdletBinding()]` + `param()` for any function with > 1 parameter. -- **Pure-logic functions go in the `Core` region** of `SnipIT.ps1` so the headless test suite picks them up via `-CoreOnly`. +- **`src/` and `xaml/` are the authoritative sources; `SnipIT.ps1` is generated.** Never edit `SnipIT.ps1` directly — change the source, then run `pwsh -NoProfile -File ./Build-SnipIT.ps1` and commit the source change and regenerated distribution together. CI rebuilds and rejects a stale `SnipIT.ps1`. +- **Pure-logic functions go in `src/00-Core.ps1`** so the headless test suite picks them up via `-CoreOnly`; `-CoreOnly` must stay usable on Linux without loading WPF or other Windows-only assemblies. - **Preview-window event handlers are one-line wrappers** around named closures captured at window-creation time (e.g. `$beginPan`, `$pickColor`, `$handleMouseDown`) — keeps the test harness able to drive every code path through the closures via `-TestAction`. - **Tests are zero-dependency** (no Pester). Follow the assertion pattern in `Test-SnipIT.ps1`. -- **Single-file deliverable is a headline product feature.** Do not propose splitting `SnipIT.ps1` into modules without an explicit board reversal. +- **The single-file distribution is a headline product feature.** `SnipIT.ps1` must stay portable: no runtime lookup of `src/`, `xaml/`, the builder, repository paths, external modules, or network resources. ## What you'll need @@ -61,7 +62,6 @@ For larger changes (new region in `SnipIT.ps1`, new top-level function group, ne ## Documentation - Update [`CHANGELOG.md`](CHANGELOG.md) `[Unreleased]` section with an entry under **Added** / **Changed** / **Fixed** / **Security** as appropriate. -- If your PR changes how to build/test/run, conventions, gotchas, or introduces a new dependency, also update [`CLAUDE.md`](CLAUDE.md). It is the agent / contributor brief read at session start. -- Long-form docs go under [`docs/`](docs/README.md). +- If your PR changes how to build/test/run, conventions, or introduces a new dependency, also update [`README.md`](README.md) — it is the documentation entry point. Thanks again — the project is small, the test suite is fast, and your PR will get a reply quickly. diff --git a/README.md b/README.md index a2f9bb7f3..329df76bf 100644 --- a/README.md +++ b/README.md @@ -1,238 +1,53 @@ -# SnipIT +# snipIT -[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/12647/badge)](https://www.bestpractices.dev/en/projects/12647) -[![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/RandomCodeSpace/snipIT/badge)](https://securityscorecards.dev/viewer/?uri=github.com/RandomCodeSpace/snipIT) -[![Security (OSS-CLI)](https://img.shields.io/github/actions/workflow/status/RandomCodeSpace/snipIT/security.yml?branch=main&label=Security%20%28OSS-CLI%29&logo=github)](https://github.com/RandomCodeSpace/snipIT/actions/workflows/security.yml) -[![PowerShell 7.5+](https://img.shields.io/badge/PowerShell-7.5%2B-5391FE?logo=powershell&logoColor=white)](https://github.com/PowerShell/PowerShell) -[![.NET 9](https://img.shields.io/badge/.NET-9-512BD4?logo=dotnet&logoColor=white)](https://dotnet.microsoft.com/) -[![Windows 11](https://img.shields.io/badge/Windows-11-0078D4?logo=windows11&logoColor=white)](https://www.microsoft.com/windows/windows-11) -[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE) -[![Tests](https://img.shields.io/badge/tests-CI%20passing-brightgreen)](#tests) -[![No Admin](https://img.shields.io/badge/admin-not%20required-success)](#install) -[![Single File](https://img.shields.io/badge/single%20file-yes-informational)](SnipIT.ps1) +**Capture. Annotate. Share.** A professional snipping tool for Windows 11, written entirely in PowerShell — one script, zero dependencies, no admin rights. -A **professional snipping tool** for Windows 11 written in **pure PowerShell 7.5+** on **.NET 9**. Hover-to-highlight smart capture, magnifier loupe, floating widget, system tray, chromeless Fluent preview with a full annotation editor — all in a single script with **zero external dependencies** and **no admin elevation**. +[![Tests](https://github.com/RandomCodeSpace/snipIT/actions/workflows/test.yml/badge.svg)](https://github.com/RandomCodeSpace/snipIT/actions/workflows/test.yml) +[![Security](https://github.com/RandomCodeSpace/snipIT/actions/workflows/security.yml/badge.svg)](https://github.com/RandomCodeSpace/snipIT/actions/workflows/security.yml) +[![OpenSSF Best Practices](https://www.bestpractices.dev/projects/12647/badge)](https://www.bestpractices.dev/projects/12647) +[![License: MIT](https://img.shields.io/badge/License-MIT-blue.svg)](LICENSE) -## Features +## Why snipIT -### Capture +- **Smart capture** — hover highlights whole windows, drag selects a region, a magnifier loupe gives you pixel-perfect edges. Mixed-DPI multi-monitor setups just work. +- **Annotate in place** — arrows, boxes, highlights, text, and blur in a non-destructive editor with full undo. +- **Fluent by default** — follows your system Light/Dark theme with a native Windows 11 look. +- **One file** — `SnipIT.ps1` is the entire app. Clone and run; nothing to install, no elevation, no telemetry. -- **Smart capture** — hover any window to highlight it and click to grab, or drag for a custom region. One overlay, two gestures, with a **pixel-perfect magnifier loupe** and live screen-coordinate readout. -- **Full virtual-desktop capture** spanning all monitors (handles negative-origin layouts). -- **Active window capture** — grabs the foreground window by its exact window rect. -- **DPI-aware capture** — requests per-monitor (V2) DPI awareness at startup. If the host process already has a DPI awareness set (some managed environments pre-initialize it), Windows denies the request and SnipIT runs system-DPI aware; captures stay correct on uniform-DPI setups, while mixed-DPI monitors are captured through Windows' DPI virtualization. - -### Preview window - -- **Chromeless Fluent UI** — WPF Fluent theme, Segoe Fluent Icons, draggable header, pin-on-top, resizable, maximizable. -- **Zoom** — Zoom In / Zoom Out / Fit-to-viewport buttons, `Ctrl + +`, `Ctrl + -`, `Ctrl + 0`, and **Ctrl + mouse-wheel** all work. Range 5 % – 1000 %. Live zoom indicator in the header. -- **Pan (Hand) mode** — the default when no annotation tool is selected: click and drag anywhere on the image to scroll a zoomed-in view. Cursor auto-switches between Hand and Cross. - -### Annotations - -- **Four annotation tools**: Highlight, Rectangle, Arrow, Text -- **Six-color palette** (yellow / green / pink / blue / orange / red) with live in-place color updates — change color while typing a text annotation and the foreground swaps immediately -- **Undo / Redo** with full history (`Ctrl+Z` / `Ctrl+Shift+Z`) -- **Right-click any annotation** to change its color or delete it -- **Clear all** button to wipe the annotation layer -- Annotations are stored in **image-pixel coordinates** so they survive zoom and export cleanly - -### Output - -- **Copy to clipboard** — flattened with all annotations baked in (`Ctrl+C`) -- **Save as** — PNG / JPG / BMP, default path `~\Pictures\Snips\snip-yyyyMMdd-HHmmss.png` (`Ctrl+S`) -- **New snip** — close the preview and start a fresh capture (`Ctrl+N`) - -### System integration - -- **System tray** with full menu (capture modes, open snips folder, about, uninstall, exit) -- **Floating capture widget** — auto-hiding top-center pill with Smart/Full/Window buttons -- **One configurable Smart-capture hotkey** registered via `RegisterHotKey` on a hidden message-only form; Full and Window capture stay available from the tray -- **Single-instance** enforced by a per-session named mutex; a second launch shows a friendly message instead of stacking up -- **Self-installing**: first launch copies the app and durable settings to `%LOCALAPPDATA%\SnipIT`, creates a Desktop shortcut, and synchronizes the `shell:startup` shortcut from the `LaunchAtSignIn` setting. **No admin. No UAC prompts.** - -## Hotkeys - -### Global - -| Hotkey | Action | -|---|---| -| `Ctrl+Alt+Shift+Q` | Smart capture (hover-window or drag-region) | -| `Esc` / right-click | Cancel an active capture | - -Full virtual-desktop and active-window capture intentionally have no global hotkey; use the system-tray menu for those modes. - -### Preview window - -| Hotkey | Action | -|---|---| -| `Ctrl+C` | Copy flattened image to clipboard | -| `Ctrl+S` | Save as PNG / JPG / BMP | -| `Ctrl+N` | New snip | -| `Ctrl+Z` / `Ctrl+Shift+Z` | Undo / Redo | -| `Ctrl + +` / `Ctrl + -` | Zoom in / out | -| `Ctrl + 0` | Reset zoom to 100 % | -| `Ctrl + mouse-wheel` | Zoom centered on cursor | -| `Esc` | Close preview | - -## Install - -1. Make sure you have **PowerShell 7.5+** and **Windows 11** (`pwsh --version`) -2. Download `SnipIT.ps1` -3. Double-click it (or run `pwsh -Sta -File .\SnipIT.ps1`) - -On first run SnipIT silently: -- Copies itself to `%LOCALAPPDATA%\SnipIT\SnipIT.ps1` -- Creates `%LOCALAPPDATA%\SnipIT\settings.json` for the Smart hotkey, save defaults, widget visibility, and launch-at-sign-in preference -- Creates a Desktop shortcut -- Creates or removes the `shell:startup` shortcut to match `LaunchAtSignIn` (enabled by default) -- Generates a `SnipIT.ico` on the fly -- Shows a tray balloon: *"SnipIT installed. Press Ctrl+Alt+Shift+Q to capture."* - -To **uninstall**: right-click the tray icon → *Uninstall*. Removes both shortcuts and the `%LOCALAPPDATA%\SnipIT` folder. - -## Usage - -After installation, SnipIT runs in the system tray. Press `Ctrl+Alt+Shift+Q`, hover the window you want, click. The preview window opens with the captured image. From there: - -- **Annotate** — click a tool, pick a color, drag on the image. Click the active tool again (or `Esc`) to return to pan mode. -- **Zoom in to detail** — `Ctrl + mouse-wheel` or the zoom buttons; then drag the image to pan around. -- **Change an existing annotation** — right-click it to pick a new color or delete it. -- **Type a text annotation** — click the Text tool, click on the image, type, click a different color mid-typing to re-color live, press Enter to commit (or click elsewhere). Escape discards. -- **Copy or save** — `Ctrl+C` / `Ctrl+S`, or the toolbar buttons. -- **New snip** — `Ctrl+N` or the toolbar button to close the preview and drop straight back into the capture overlay. - -## Architecture - -SnipIT keeps a portable single-file distribution while using modular, -reviewable development sources. The ownership and generation flow is: - -``` -src/*.ps1 + xaml/*.xaml - │ - ▼ - Build-SnipIT.ps1 - │ - ▼ - SnipIT.ps1 -``` - -- `src/00-Core.ps1` owns cross-platform pure logic and the `-CoreOnly` boundary. -- `src/10-Bootstrap.ps1` owns startup, settings, installation, and XAML loading. -- `src/20-Native.ps1`, `src/30-Capture.ps1`, `src/40-Preview.ps1`, - `src/50-Tray.ps1`, and `src/90-Main.ps1` own their named runtime layers. -- The six files in `xaml/` own UI markup. -- `Build-SnipIT.ps1` is the sole authority for module/XAML order and generation. - -`SnipIT.ps1` is generated, checked in, portable, and has no runtime dependency -on the repository. Never edit it directly; edit `src/` or `xaml/` and rebuild. - -## Development +## Quick start ```powershell -# Run authoritative modular development sources (Windows) -pwsh -Sta -File ./SnipIT.Dev.ps1 - -# Regenerate the portable checked-in release -pwsh -NoProfile -File ./Build-SnipIT.ps1 +git clone https://github.com/RandomCodeSpace/snipIT.git +cd snipIT +pwsh -Sta -File ./SnipIT.ps1 ``` -Commit the regenerated `SnipIT.ps1` with every source or XAML change. CI runs -the builder and rejects a stale release with `git diff --exit-code -- SnipIT.ps1`. - -### Preview-window internals +First launch adds a tray icon and registers the global hotkey. -The preview window's mouse interaction, zoom, text-editing and color-picking are all organized as **named closures** captured at window-creation time (`$beginPan`, `$updatePan`, `$endPan`, `$beginDraw`, `$updateDraw`, `$finishDraw`, `$openText`, `$pickColor`, `$handleMouseDown`, `$setZoom`, `$zoomBy`, `$fitToViewport`). The real WPF event handlers are one-line wrappers that compute mouse positions and delegate to these closures. This keeps the event handlers trivial and — more importantly — gives the test harness a way to drive every code path without synthesizing real `MouseButtonEventArgs`. - -`Show-PreviewWindow` accepts an optional `-TestAction [scriptblock]` parameter that runs the callback during `Loaded` (while `ShowDialog` is blocking, so function-local variables stay alive) and then closes the window off-screen. The interactive harness uses this to run end-to-end tests against a headless preview window. - -Setting the environment variable `SNIPIT_TEST_MODE=1` before dot-sourcing the -generated release or development launcher short-circuits installation and -shortcut writes as well as the single-instance mutex, tray setup, hotkey -registration, and main loop, so a harness can load functions without side effects. +| Shortcut | Action | +|---|---| +| `Ctrl+Alt+Shift+Q` | Smart capture (hover a window or drag a region) | +| `Esc` | Cancel capture | +| `Ctrl+Z` / `Ctrl+Y` | Undo / redo in the editor | +| `Ctrl+0` / `Ctrl+±` | Fit / zoom in the editor | -## Tests +## Building from source -All suites are zero-dependency (no Pester). The harness reports current totals -at runtime, so this documentation does not become stale as coverage grows. +`src/` and `xaml/` are the authoritative sources; `SnipIT.ps1` is generated. ```powershell -# Build/generation contract and failure fixtures (any platform) -pwsh -NoProfile -File .\Test-SnipIT-Build.ps1 - -# Pure-logic suite against the generated release (any platform) -pwsh -NoProfile -File .\Test-SnipIT.ps1 - -# Pure-logic parity against authoritative development sources -$env:SNIPIT_SCRIPT_UNDER_TEST = '.\SnipIT.Dev.ps1' -pwsh -NoProfile -File .\Test-SnipIT.ps1 - -# Full generated-release WPF suite (Windows only) -Remove-Item Env:SNIPIT_SCRIPT_UNDER_TEST -ErrorAction Ignore -pwsh -NoProfile -Sta -File .\Test-SnipIT-Interactive.ps1 - -# Focused development-launcher WPF smoke (Windows only) -$env:SNIPIT_SCRIPT_UNDER_TEST = '.\SnipIT.Dev.ps1' -$env:SNIPIT_TEST_GROUP = 'Floating Studio preview shell' -pwsh -NoProfile -Sta -File .\Test-SnipIT-Interactive.ps1 -Remove-Item Env:SNIPIT_TEST_GROUP,Env:SNIPIT_SCRIPT_UNDER_TEST +pwsh -NoProfile -File ./Build-SnipIT.ps1 # regenerate the distribution +pwsh -NoProfile -File ./Test-SnipIT.ps1 # pure-logic tests (Linux + Windows) +pwsh -NoProfile -Sta -File ./Test-SnipIT-Interactive.ps1 # WPF integration tests +pwsh -NoProfile -File ./Test-SnipIT-Build.ps1 # build determinism contract ``` -### `Test-SnipIT-Build.ps1` - -Locks manifest order, module/function parity, embedded XAML parity, deterministic -generation, formatting, provenance, parser safety, and transactional failure behavior. - -### `Test-SnipIT.ps1` +Never edit `SnipIT.ps1` directly — change `src/`/`xaml/` and rebuild. CI rejects a stale distribution. -Covers pure logic and behavioral contracts through `-CoreOnly`, against either -`SnipIT.ps1` or the injected `SNIPIT_SCRIPT_UNDER_TEST` development launcher. +## Contributing -### `Test-SnipIT-Interactive.ps1` - -Drives a real off-screen preview window via `-TestAction`. Coverage: - -- **Zoom** — `SetZoom`, `ZoomBy`, compounded zoom, clamps (0.05 / 10), `ZoomText` update, `FitToViewport` -- **Pan** — default Hand cursor, drag → `Scroller` offset, `EndPan` cursor restore, no-op when not panning -- **Tool selection** — Highlight / Rect / Text interlock, cursor switching -- **Drawing** — highlight / rect / arrow with coord mapping at 1× and 2× zoom, short-arrow auto-discard -- **Colors** — all six palette entries applied to new annotations via `ActiveColor` and via `PickColor` -- **Undo / Redo** -- **Hit test** — `Find-AnnotationAt` topmost wins, outside returns -1 -- **Flattening** — `Get-FlattenedBitmap` dimensions and type -- **Full click dispatch** via `HandleMouseDown` — pan / draft / text / out-of-bounds / editing-text branches -- **Text tool** — `OpenText` creates a TextBox; empty commit discards; typed commit appends annotation; live `PickColor` foreground swap during editing; `Render-Annotations` applies `annotation.Color` to the rendered TextBlock - -## Project files - -| File / folder | Purpose | -|---|---| -| `src/` | Authoritative PowerShell implementation modules | -| `xaml/` | Authoritative WPF markup | -| `Build-SnipIT.ps1` | Deterministic manifest, embedding, validation, and release generator | -| `SnipIT.Dev.ps1` | Development launcher for authoritative repository sources | -| `SnipIT.ps1` | Generated, checked-in, standalone distribution; never edit directly | -| `Test-SnipIT-Build.ps1` | Build determinism and failure-contract fixtures | -| `Test-SnipIT.ps1` | Cross-platform pure-logic tests, no dependencies | -| `Test-SnipIT-Interactive.ps1` | Windows WPF integration tests, no dependencies | -| [`docs/`](docs/) | Long-form docs (design mocks, deeper write-ups). [`docs/README.md`](docs/README.md) is the index. | -| [`CHANGELOG.md`](CHANGELOG.md) | Per-merge change history ([Keep a Changelog](https://keepachangelog.com/en/1.1.0/) format). | -| [`SECURITY.md`](SECURITY.md) | Vulnerability disclosure policy + supported versions. | -| [`AGENTS.md`](AGENTS.md) | Authoritative agent/contributor brief and engineering constraints | -| [`CLAUDE.md`](CLAUDE.md) | Compatibility pointer to `AGENTS.md` | -| [`shared/runbooks/engineering-standards.md`](shared/runbooks/engineering-standards.md) | PowerShell variant of the company-canonical engineering-standards runbook. | -| [`.bestpractices.json`](.bestpractices.json) | OpenSSF Best Practices self-assessment (project [12647](https://www.bestpractices.dev/en/projects/12647)). | -| `LICENSE` | MIT | - -## Roadmap - -- Scrolling / long-page capture -- Blur / pixelate annotation -- OCR via `Windows.Media.Ocr` — copy text from a snip -- Persisted preferences (rebindable hotkeys, default save folder, widget position) -- Capture-history gallery -- Drag-and-drop the snip out to other apps (Slack, Teams, file explorer) +See [CONTRIBUTING.md](CONTRIBUTING.md). Security reports: [SECURITY.md](SECURITY.md). Releases: [CHANGELOG.md](CHANGELOG.md). ## License -MIT — see [LICENSE](LICENSE). +[MIT](LICENSE) diff --git a/SECURITY.md b/SECURITY.md index 954ba4ec9..e610a4ffa 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -53,7 +53,7 @@ Out of scope: ## Hardening references -- [`shared/runbooks/engineering-standards.md`](shared/runbooks/engineering-standards.md) — CVE policy and quality gates. +- [`CONTRIBUTING.md`](CONTRIBUTING.md) — CVE policy and quality gates. - `.github/workflows/scorecard.yml` — OpenSSF Scorecard supply-chain checks. - `.github/workflows/security.yml` — OSS-CLI security stack: Trivy (filesystem), Semgrep (SAST), PSScriptAnalyzer (PowerShell lint), Gitleaks (secrets), jscpd (duplication), `anchore/sbom-action` (SBOM). - GitHub repo-level **secret scanning + push protection** — enabled under repo Settings → Code security. diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index 569f1aff6..000000000 --- a/docs/README.md +++ /dev/null @@ -1,30 +0,0 @@ -# snipIT documentation - -This folder collects long-form documentation that doesn't fit in the top-level [`README.md`](../README.md), the agent / contributor brief in [`CLAUDE.md`](../CLAUDE.md), or the disclosure policy in [`SECURITY.md`](../SECURITY.md). - -snipIT is intentionally a **single-script** product (`SnipIT.ps1`); most of what you need to know lives in the regions inside that script. The files here capture material that is too large or too visual to live alongside the code. - -## Index - -| Path | What it is | -|---|---| -| [`mockups/preview-redesign.html`](mockups/preview-redesign.html) | Standalone HTML mock of the chromeless Fluent preview window — used as the design reference when iterating on the WPF preview chrome. Open it in any browser. | - -## Documentation in other places - -For convenience, here is where the rest of snipIT's docs live: - -| Topic | Where to read it | -|---|---| -| Install, hotkeys, usage, architecture overview | [`/README.md`](../README.md) | -| Build, test, run; conventions; gotchas; OpenSSF Scorecard baseline | [`/CLAUDE.md`](../CLAUDE.md) | -| Vulnerability disclosure, supported versions, scope | [`/SECURITY.md`](../SECURITY.md) | -| Quality gates, security tooling, branch / commit / PR rules | [`/shared/runbooks/engineering-standards.md`](../shared/runbooks/engineering-standards.md) — the PowerShell variant of the company-canonical engineering-standards runbook | -| Per-merge change history | [`/CHANGELOG.md`](../CHANGELOG.md) | -| OpenSSF Best Practices self-assessment (machine-readable) | [`/.bestpractices.json`](../.bestpractices.json) — companion to project [12647](https://www.bestpractices.dev/en/projects/12647) | - -## Contributing documentation - -If you're adding a doc that explains design rationale, walks through a non-trivial subsystem, or captures a decision (ADR-style), add a sibling file under `docs/` and link it from the **Index** table above. Keep this README the single entry point so the table of contents stays discoverable. - -For docs that belong with the code itself (region-level comments inside `SnipIT.ps1`, function-level help blocks), prefer inline comments per the convention in [`shared/runbooks/engineering-standards.md`](../shared/runbooks/engineering-standards.md) §2. diff --git a/docs/mockups/preview-redesign.html b/docs/mockups/preview-redesign.html deleted file mode 100644 index 4f90d0199..000000000 --- a/docs/mockups/preview-redesign.html +++ /dev/null @@ -1,502 +0,0 @@ - - - - - -SnipIT preview — redesign mock - - - - -

SnipIT preview — redesign mock

-

- Side-by-side with the current layout. Notion-inspired: warm near-black, - thin dividers, icon-first tools with labels in tooltips, typography - condensed to a three-step scale, active state as a 2px underline rather - than a solid accent fill. No emoji, no novelty, just less chrome. -

- -
- - -
-

Current

-
-
-
- - SnipIT - 1920 × 1080 px - 100% -
-
- - - - -
-
- -
- -
- - - - -
-
-
-
-
-
-
-
-
- - - -
- -
- - - - -
-
-
- Four stacked rows of chrome — header, viewport, annotation toolbar, - action row. Windows accent #0078D4, solid fill on active - tool, 8 hex literals scattered across 4 XAML blobs. -
-
- - -
-

Redesign

-
- - -
-
- SnipIT - - 1920 × 1080 - - 100% -
-
- - - -
- - -
-
- -
- - -
- -
- - - - -
- -
- -
-
-
-
-
-
-
-
- -
- -
- - - -
- -
- - - - - -
-
- -
- Two rows of chrome: top bar 44px, toolbar 44px. - Active tool uses a 2px accent underline (#5B8DEF) on a - subtle translucent fill, not a solid accent block. Swatches are 14px - circles — active gets a 2px outline ring. Copy is the only primary - action; Save / New are ghosts. Close moves to the top bar so the - action cluster holds only creation verbs. -
-
- -
- -
-
-

Palette

-

#17181A window bg

-

#1E1F22 elevated surface

-

#2A2B2E subtle divider

-

#E8E8EA / #9A9AA0 / #6B6B70 three-step text

-

#5B8DEF accent — cool desaturated blue, distinct from Windows #0078D4

-
-
-

Typography

-

Three sizes only: 11 / 13 / 15. Weights 400 / 500 / 600.

-

Inter → Segoe UI → system-ui fallback. Tabular numerals for dimensions & zoom.

-

No inline text labels on tool buttons — they live in tooltips.

-
-
-

Density & layout

-

Four-row chrome collapses to two: top bar + toolbar. ~80 vertical pixels reclaimed on a 700px-tall preview.

-

Groups are separated by a 1px hairline, not by docking to opposite edges.

-

Copy = primary (filled). Save / New = ghost. Close moves to top bar as icon.

-
-
- - - diff --git a/scripts/setup-git-signed.sh b/scripts/setup-git-signed.sh index 07c1921d7..e7381de1d 100755 --- a/scripts/setup-git-signed.sh +++ b/scripts/setup-git-signed.sh @@ -1,7 +1,7 @@ #!/usr/bin/env bash # scripts/setup-git-signed.sh # -# Apply the repo-local git config required by `shared/runbooks/engineering-standards.md` §8 +# Apply the repo-local git config required by `CONTRIBUTING.md` (signed commits) # Supports BOTH ssh-format and openpgp-format signing — picks up # whichever the contributor already has wired into their global git config. # diff --git a/shared/runbooks/engineering-standards.md b/shared/runbooks/engineering-standards.md deleted file mode 100644 index 4de95e7df..000000000 --- a/shared/runbooks/engineering-standards.md +++ /dev/null @@ -1,110 +0,0 @@ -# Engineering Standards — snipIT - -PowerShell variant of the canonical company runbook. Adapts the OSS-CLI tooling stack for a single-file PowerShell 7.5+ project on .NET 9; everything else is inherited from the canonical runbook. - -- **Policy owner:** TechLead. -- **Producers:** anyone landing PRs on `main`. -- **Reviewers:** TechLead (Codex pass) + CI gates. - -If a CI gate enforces it, the engineer fixes — do not lower the gate. - ---- - -## 1. Quality gates (hard / non-negotiable) - -| Gate | Threshold | Where it runs | Failure action | -|---|---|---|---| -| Headless tests (`Test-SnipIT.ps1`) | All pass on Linux + Windows runners | `.github/workflows/test.yml` | Block merge | -| Script parses cleanly (Windows AST) | 0 parser errors | `.github/workflows/test.yml` (`parse` job) | Block merge | -| **PSScriptAnalyzer (PowerShell lint)** | **Zero `Error`-severity findings on `SnipIT.ps1`** | `.github/workflows/security.yml` (`psscriptanalyzer` job) | Block merge | -| Trivy (filesystem scan) | Zero High/Critical findings (`severity: HIGH,CRITICAL`, `exit-code: 1`) | `.github/workflows/security.yml` | Block merge | -| Semgrep (SAST) | Zero ERROR-level findings on `p/security-audit` + `p/owasp-top-ten` | `.github/workflows/security.yml` | Block merge | -| Gitleaks (secret scan, full git history) | Zero findings | `.github/workflows/security.yml` | Block merge | -| jscpd (duplication) | < 3% on production code (`SnipIT.ps1`) | `.github/workflows/security.yml` | Block merge | -| SBOM (SPDX + CycloneDX) | Generated and uploaded as build artifact (`anchore/sbom-action`) | `.github/workflows/security.yml` | Surface as artifact; do **not** gate merge | -| Dependabot (GitHub Actions ecosystem) | Surfaces advisories on `.github/workflows/*` actions pinning | `.github/dependabot.yml` + repo Security tab | Surface; auto-PRs gated by separate review | -| OpenSSF Scorecard | Best-effort; no hard score floor; `Pinned-Dependencies` is a soft target | `.github/workflows/scorecard.yml` (push to `main` + weekly) | Surface in security tab; do **not** gate merge | -| Signed commits | Every commit on `main` must verify | Branch protection + `scripts/setup-git-signed.sh` | Block merge | - -**Stack: OSS-CLI only.** Per the company runbook (path B): no Sonar, no CodeQL, no NVD-direct tools. The OSS-CLI stack covers the same ground without those issues; cost is $0 in GitHub Actions for public OSS. - -**No SCA against a lockfile.** snipIT is a single `.ps1` script with **zero external runtime dependencies** — no npm / Maven / pip / NuGet manifest, so the OSV-Scanner job from the codeiq reference is intentionally **omitted**. Trivy filesystem scan covers any future deps; Dependabot covers the GitHub Actions ecosystem (the only versioned deps in the repo today). - -## 2. Code style - -- Pure PowerShell 7.5+ on .NET 9. No PowerShell 5.1 fallbacks; no `Add-Type` stubs that only work on Windows PowerShell. -- Functions follow `Verb-Noun` PascalCase per [PowerShell approved verbs](https://learn.microsoft.com/powershell/scripting/developer/cmdlet/approved-verbs-for-windows-powershell-commands). -- Use `[CmdletBinding()]` + `param()` blocks for any function with > 1 parameter. Mandatory parameters declared explicitly. -- Strict mode: scripts that should run under `Set-StrictMode -Version Latest` declare it at top of scope. -- Single-file deliverable is a **headline feature** of snipIT — do not split `SnipIT.ps1` into modules without an explicit board reversal. - -## 3. Branch, commit, PR rules - -- See company runbook §7 (branch protection) and §8 (signed commits). All commits on `main` are signed; force-push and direct-push to `main` are disabled; squash-merge is the only allowed merge style. -- Run `scripts/setup-git-signed.sh` once per worktree to apply the local git config. The script honours your existing global signing setup (ssh / openpgp / x509). - -## 4. Testing tiers - -- **Headless** — `Test-SnipIT.ps1` runs pure-logic tests (no UI / WPF / hotkey registration). Gated in CI on Linux + Windows runners. -- **Interactive** — `Test-SnipIT-Interactive.ps1` exercises preview-window + capture flows. Run locally on Windows; not in CI. -- New behaviour ships with at least one headless test where the logic is testable without a desktop session. UI-only paths are documented in `README.md` under `Tests`. - -## 5. Security - -### 5.1 Tooling stack — OSS-CLI ONLY (PowerShell variant) - -| Concern | Tool | Where | -|---|---|---| -| PowerShell lint | **PSScriptAnalyzer** (`Invoke-ScriptAnalyzer -Severity Error`) | `.github/workflows/security.yml` | -| Filesystem CVE scan | **Trivy** filesystem scan (HIGH / CRITICAL gating) | `.github/workflows/security.yml` | -| SAST | **Semgrep** (`p/security-audit`, `p/owasp-top-ten`) | `.github/workflows/security.yml` | -| Secret scan | **Gitleaks** (full git history) | `.github/workflows/security.yml` | -| Duplication | **jscpd** (PowerShell, threshold < 3%, `--min-tokens 100`) | `.github/workflows/security.yml` | -| SBOM | **`anchore/sbom-action`** (SPDX + CycloneDX) | `.github/workflows/security.yml` | -| Dependency updates | **Dependabot** (GitHub Actions ecosystem, weekly, grouped) | `.github/dependabot.yml` | -| Supply-chain score | **OpenSSF Scorecard** (`ossf/scorecard-action`, push + weekly) | `.github/workflows/scorecard.yml` | - -**Not used (do not re-introduce without an explicit board reversal):** SonarCloud / SonarQube, CodeQL (no PowerShell pack today; Semgrep + PSScriptAnalyzer cover the SAST + lint surface), OSV-Scanner (no lockfile to scan), OWASP Dependency-Check (NVD-direct). - -### 5.2 Code hygiene - -- **P/Invoke surface** — every `Add-Type @"…"@` block that imports `user32.dll` / `gdi32.dll` / `kernel32.dll` is reviewed for input-handle validation; never pass user-controlled HWNDs without owner-check. -- **Path handling** — anything that takes a user-supplied save path (e.g. the file-save dialog handler) goes through `Resolve-Path` + canonical-form check before write. -- **Secrets** — never in code, config, or commit history. Gitleaks runs full-history. -- **CVE policy** — High/Critical → block; Medium → fix if a patched version exists, else document non-exploitability with TechLead sign-off; Low → tracked in the next dependency-bump cycle. -- **Vulnerability reporting** — see [`/SECURITY.md`](../../SECURITY.md). Private disclosure only. - -## 6. Performance - -- Capture path target: end-to-end snip (key-press → preview window painted) **< 250 ms** on a clean Windows 11 desktop. Measure with `Measure-Command` around `Invoke-FullScreenCapture` / `Invoke-WindowCapture`; do not regress. -- Preview window: zoom / pan / annotation hit-test ≤ **16 ms** per frame (60 fps target on a 4K monitor). -- No unbounded buffers: capture pipeline disposes `System.Drawing.Bitmap` instances on every iteration of `Invoke-CaptureLoop`; the preview takes ownership and disposes on close (capture-ownership contract). - -## 7. Build & distribution - -- snipIT is a single `.ps1` — there is no compile / package step. The deliverable is the script in the repo. -- Install flow generates a runtime install home next to the script (icon + cached copy + `last-error.txt`). Documented in `README.md` under `Install`. The install flow is the only on-disk side-effect outside the user's chosen save path. -- No public-CDN runtime fetches, no auto-update phone-home, no telemetry. -- GitHub Actions are pinned by commit SHA in every workflow. Rationale: OpenSSF Scorecard `Pinned-Dependencies` and supply-chain integrity. - -## 8. Documentation - -- `README.md` — install, hotkeys, usage, architecture overview, badges. -- `CLAUDE.md` — agent brief: architecture, build/test/run commands, conventions, gotchas, **OpenSSF Scorecard baseline + target**. -- `SECURITY.md` — disclosure policy, supported versions, scope. -- `docs/` — design notes, screenshots, mock-ups. -- `shared/runbooks/engineering-standards.md` — this file (the PowerShell variant of the company runbook). - -## 9. References - -- Company canonical engineering-standards runbook (parent of this file). -- `/CLAUDE.md` — architecture and conventions. -- `/SECURITY.md` — disclosure policy. -- `/home/dev/.claude/rules/*.md` — global engineering rules (parent SSoT). -- `.github/workflows/` — CI / security / supply-chain automations: - - `test.yml` — headless tests + Windows AST parse. - - `security.yml` — OSS-CLI security stack (PSScriptAnalyzer, Trivy, Semgrep, Gitleaks, jscpd, SBOM). - - `scorecard.yml` — OpenSSF Scorecard (push + weekly cron, non-gating). -- `scripts/setup-git-signed.sh` — repo-local signed-commit setup. -- OpenSSF Best Practices: . -- OpenSSF Scorecard dashboard: .