{"id":50727202,"url":"https://github.com/wrg-11/devguard-scan","last_synced_at":"2026-06-10T05:01:43.647Z","repository":{"id":361452507,"uuid":"1254472351","full_name":"WRG-11/devguard-scan","owner":"WRG-11","description":"100% client-side secret scanner — a dependency-free, zero-upload browser port of the wrg-devguard scan engine. Paste code or drop files; nothing leaves your browser.","archived":false,"fork":false,"pushed_at":"2026-06-09T03:17:35.000Z","size":45,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-09T05:13:23.653Z","etag":null,"topics":["client-side","devsecops","privacy","secret-scanning","security","static-site","zero-dependency"],"latest_commit_sha":null,"homepage":"https://wrg-11.github.io/devguard-scan/","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/WRG-11.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-30T15:57:03.000Z","updated_at":"2026-06-09T03:17:39.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/WRG-11/devguard-scan","commit_stats":null,"previous_names":["wrg-11/devguard-scan"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/WRG-11/devguard-scan","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WRG-11%2Fdevguard-scan","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WRG-11%2Fdevguard-scan/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WRG-11%2Fdevguard-scan/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WRG-11%2Fdevguard-scan/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/WRG-11","download_url":"https://codeload.github.com/WRG-11/devguard-scan/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/WRG-11%2Fdevguard-scan/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34137570,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-10T02:00:07.152Z","response_time":89,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["client-side","devsecops","privacy","secret-scanning","security","static-site","zero-dependency"],"created_at":"2026-06-10T05:01:42.692Z","updated_at":"2026-06-10T05:01:43.636Z","avatar_url":"https://github.com/WRG-11.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# devguard-in-browser\r\n\r\nA **100% client-side** secret scanner. Paste code or drop files; it flags leaked\r\nAPI keys, tokens, and private-key blocks **without a single byte leaving your\r\nbrowser**. It is a static, dependency-free port of the `wrg_devguard`\r\n`scan-secrets` engine — the same \u003c!-- METRIC:secret_rule_count --\u003e10\u003c!-- /METRIC:secret_rule_count --\u003e rules, the same include/exclude logic, the\r\nsame line/column reporting.\r\n\r\n\u003e **POC / demo.** A \"try-it-now\" capability demo of the engine, not a product.\r\n\r\n## Why it's interesting\r\n\r\n- **0-byte upload.** All scanning runs in `scan.js` in your browser. There is no\r\n  `fetch`, `XMLHttpRequest`, `WebSocket`, `sendBeacon`, analytics, or external\r\n  CDN anywhere in the source. Open the DevTools **Network** tab, scan a file,\r\n  and you will see **zero** requests after the initial page load.\r\n- **Secrets are never shown.** Every match is reported as `[REDACTED]`; the raw\r\n  secret value never enters the results table, the DOM, or any payload (parity\r\n  with `secrets.py:107`).\r\n- **Detection parity** with the canonical Python tool, proven by a test harness\r\n  (see below) — not just visually similar.\r\n\r\n## Run it\r\n\r\nIt uses ES modules, so serve it over http (modules are blocked on `file://`):\r\n\r\n```powershell\r\n# from the repo root\r\npy -3 -m http.server 8080\r\n# then open http://localhost:8080/\r\n```\r\n\r\nAny static host (GitHub Pages, Netlify, S3) works the same way — a live\r\ninstance runs at \u003chttps://wrg-11.github.io/devguard-scan/\u003e. After the page\r\nloads, you can disconnect from the network entirely — it keeps working.\r\n\r\n## What it detects (\u003c!-- METRIC:secret_rule_count --\u003e10\u003c!-- /METRIC:secret_rule_count --\u003e rules — ported verbatim)\r\n\r\n| rule_id                     | severity | source                  |\r\n|-----------------------------|----------|-------------------------|\r\n| `openai_api_key`            | ERROR    | `secrets.py` SECRET_RULES |\r\n| `github_token`              | ERROR    | \"                       |\r\n| `aws_access_key_id`         | ERROR    | \"                       |\r\n| `slack_token`               | ERROR    | \"                       |\r\n| `private_key_block`         | ERROR    | \"                       |\r\n| `generic_secret_assignment` | WARNING  | \"                       |\r\n| `google_api_key`            | ERROR    | \"                       |\r\n| `stripe_secret_key`         | ERROR    | \"                       |\r\n| `github_fine_grained_pat`   | ERROR    | \"                       |\r\n| `slack_webhook_url`         | ERROR    | \"                       |\r\n\r\nInclude/exclude follow `secrets.py` `DEFAULT_INCLUDE` + `policy.py`\r\n`DEFAULT_EXCLUDE` (e.g. `node_modules/`, `dist/`, `*.png`, `*.lock` are skipped;\r\nonly `.env/.py/.js/.json/...` extensions are scanned). The file name you assign\r\nto pasted content drives those rules.\r\n\r\n## Parity \u0026 smoke harness\r\n\r\n```powershell\r\n# from the repo root\r\npwsh -NoProfile -ExecutionPolicy Bypass -File .\\scripts\\run_parity.ps1\r\n```\r\n\r\nThe JS engine + UI smoke run standalone. To also run the **Python parity**\r\ncompare against the canonical engine, clone the public detection source and\r\npoint the harness at it:\r\n\r\n```powershell\r\ngit clone https://github.com/WRG-11/wrg-devguard\r\npwsh -NoProfile -ExecutionPolicy Bypass -File .\\scripts\\run_parity.ps1 -WrgDevguardSrc .\\wrg-devguard\\src\r\n```\r\n\r\nThis:\r\n\r\n1. Runs the **JS** engine (`scan.js`) over `fixtures/` via Node.\r\n2. Runs the **canonical Python** `wrg_devguard.secrets.scan_secrets()` over the\r\n   same `fixtures/`.\r\n3. Compares finding sets + severity counts (`rule_id`/`file`/`line`/`column`) —\r\n   exits non-zero on any divergence.\r\n4. Runs a headless UI-path smoke proving the browser glue renders findings with\r\n   `[REDACTED]` and never the raw value.\r\n\r\n\u003e The Python CLI's `--json-out` is fully redacted (counts only, no locations)\r\n\u003e for OPSEC, so parity is checked against the detection *library* directly via\r\n\u003e `scripts/py_reference_dump.py` — the same code the CLI calls.\r\n\r\n**Last run:** 9/9 findings byte-identical across the 10-rule corpus, summary\r\ncounts identical (6 ERROR + 3 WARNING); UI smoke PASS.\r\n\r\n## Fixtures\r\n\r\n`fixtures/` contains **synthetic-only** content — every \"secret\" is\r\nfake/non-functional and exists solely to exercise the 10 rules plus the\r\ninclude/exclude/no-false-positive paths. No real credential is committed.\r\n\r\n## Files\r\n\r\n```\r\nindex.html   static SPA (inline CSS, no CDN)\r\napp.js       UI glue (intake → scan → render); no network APIs\r\nscan.js      shared engine — runs in browser AND Node (single source of truth)\r\npackage.json type:module (zero runtime deps)\r\nfixtures/    synthetic parity corpus\r\nscripts/     js_reference_dump.mjs · py_reference_dump.py · parity_compare.py\r\n             ui_smoke.mjs · run_parity.ps1\r\n```\r\n\r\n## Out of scope (MVP)\r\n\r\ngit/repo clone · policy-lint / ai_check / threat checks · accounts / backend /\r\nnetwork · Pyodide · publishing/hosting. Single page, single job: secret-scan.\r\n\r\n## Phase 2 (not this POC)\r\n\r\nIf it gets traction: a Pyodide-based pattern that runs `secrets.py` (and other\r\nzero-dep WRG tools) unmodified in-browser. The public GitHub Pages host is\r\nalready live (\u003chttps://wrg-11.github.io/devguard-scan/\u003e); the Pyodide pattern\r\nstays parked until the live demo proves demand.\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwrg-11%2Fdevguard-scan","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwrg-11%2Fdevguard-scan","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwrg-11%2Fdevguard-scan/lists"}