{"_id":"@aminhanifm/issuesafe","_rev":"2-0dc4baab95fc4f5a99f3a0d2a4e454f5","name":"@aminhanifm/issuesafe","dist-tags":{"latest":"0.1.1"},"versions":{"0.1.0":{"name":"@aminhanifm/issuesafe","version":"0.1.0","keywords":["privacy","log-redaction","developer-tools","cli","typescript","security","debugging"],"author":{"name":"Amin Hanif"},"license":"MIT","_id":"@aminhanifm/issuesafe@0.1.0","maintainers":[{"name":"aminhanifm","email":"aminhanif24@gmail.com"}],"homepage":"https://aminhanifm.github.io/projects/IssueSafe/","bugs":{"url":"https://github.com/aminhanifm/IssueSafe/issues"},"bin":{"issuesafe":"dist/cli/index.js"},"dist":{"shasum":"4827132e356186325681bce9572616b45436e2e6","tarball":"https://registry.npmjs.org/@aminhanifm/issuesafe/-/issuesafe-0.1.0.tgz","fileCount":11,"integrity":"sha512-86pI6BVcWGNg9aTZlU+XwuEJY7+GpYknUoGEK6yrK/WVuN/AhBULZCBmv03sWFwbFFs1GNjHQadxEiuzpIdQrw==","signatures":[{"sig":"MEQCIFkxj+0QkdjlPB7KQVuioBJHzHoY/rnJcZHAYX0MO2ElAiAWl3r7w0mj8BNPxhVj+k/QT+qUf+oyE6WQ+lAtymrvyA==","keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U"}],"unpackedSize":115679},"type":"module","engines":{"node":">=22"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"gitHead":"64831e72bbe8bcc438ac8f265c3e46a6c0cac896","scripts":{"dev":"vite --config demo/vite.config.ts","lint":"eslint . --max-warnings=0","test":"vitest run","build":"tsup","check":"npm run format && npm run lint && npm run typecheck && npm run test:coverage && npm run build && npm run build:demo && npm run verify:package","format":"prettier --check .","preview":"vite preview --config demo/vite.config.ts","test:e2e":"playwright test","typecheck":"tsc --noEmit && tsc --noEmit -p demo/tsconfig.json && tsc --noEmit -p e2e/tsconfig.json","build:demo":"vite build --config demo/vite.config.ts","format:write":"prettier --write .","pack:dry-run":"npm pack --dry-run","test:coverage":"vitest run --coverage","verify:package":"node scripts/verify-package.mjs"},"_npmUser":{"name":"aminhanifm","email":"aminhanif24@gmail.com"},"repository":{"url":"git+https://github.com/aminhanifm/IssueSafe.git","type":"git"},"_npmVersion":"11.12.1","description":"Sanitize developer logs and create shareable bug reports without uploading anything.","directories":{},"_nodeVersion":"24.15.0","dependencies":{"commander":"^14.0.0"},"publishConfig":{"access":"public"},"_hasShrinkwrap":false,"devDependencies":{"tsup":"^8.5.0","vite":"^8.0.13","jsdom":"^29.1.1","react":"^19.2.6","eslint":"^9.39.4","vitest":"^4.0.18","globals":"^16.5.0","prettier":"^3.8.1","react-dom":"^19.2.6","@eslint/js":"^9.39.4","typescript":"^5.9.3","@types/node":"^24.10.0","@types/react":"^19.2.14","@playwright/test":"^1.58.2","@types/react-dom":"^19.2.3","typescript-eslint":"^8.56.0","@vitest/coverage-v8":"^4.0.18","@vitejs/plugin-react":"^6.0.2","@testing-library/react":"^16.3.2","@testing-library/jest-dom":"^7.0.0","eslint-plugin-react-hooks":"^7.0.1","@testing-library/user-event":"^14.6.1","eslint-plugin-react-refresh":"^0.4.26"},"_npmOperationalInternal":{"tmp":"tmp/issuesafe_0.1.0_1784664785612_0.5790824841985769","host":"s3://npm-registry-packages-npm-production"}},"0.1.1":{"name":"@aminhanifm/issuesafe","version":"0.1.1","description":"Sanitize developer logs and create shareable bug reports without uploading anything.","type":"module","license":"MIT","author":{"name":"Amin Hanif"},"repository":{"type":"git","url":"git+https://github.com/aminhanifm/IssueSafe.git"},"homepage":"https://aminhanifm.github.io/projects/IssueSafe/","bugs":{"url":"https://github.com/aminhanifm/IssueSafe/issues"},"keywords":["privacy","log-redaction","developer-tools","cli","typescript","security","debugging"],"engines":{"node":">=22"},"publishConfig":{"access":"public"},"bin":{"issuesafe":"dist/cli/bin.js"},"exports":{".":{"types":"./dist/index.d.ts","import":"./dist/index.js"}},"scripts":{"dev":"vite --config demo/vite.config.ts","build":"tsup","build:demo":"vite build --config demo/vite.config.ts","preview":"vite preview --config demo/vite.config.ts","format":"prettier --check .","format:write":"prettier --write .","lint":"eslint . --max-warnings=0","typecheck":"tsc --noEmit && tsc --noEmit -p demo/tsconfig.json && tsc --noEmit -p e2e/tsconfig.json","test":"vitest run","test:coverage":"vitest run --coverage","test:e2e":"playwright test","pack:dry-run":"npm pack --dry-run","verify:package":"node scripts/verify-package.mjs","check":"npm run format && npm run lint && npm run typecheck && npm run test:coverage && npm run build && npm run build:demo && npm run verify:package"},"dependencies":{"commander":"^14.0.0"},"devDependencies":{"@eslint/js":"^9.39.4","@playwright/test":"^1.58.2","@testing-library/jest-dom":"^7.0.0","@testing-library/react":"^16.3.2","@testing-library/user-event":"^14.6.1","@types/node":"^24.10.0","@types/react":"^19.2.14","@types/react-dom":"^19.2.3","@vitejs/plugin-react":"^6.0.2","@vitest/coverage-v8":"^4.0.18","eslint":"^9.39.4","eslint-plugin-react-hooks":"^7.0.1","eslint-plugin-react-refresh":"^0.4.26","globals":"^16.5.0","jsdom":"^29.1.1","prettier":"^3.8.1","react":"^19.2.6","react-dom":"^19.2.6","tsup":"^8.5.0","typescript":"^5.9.3","typescript-eslint":"^8.56.0","vite":"^8.0.13","vitest":"^4.0.18"},"gitHead":"2753f5a121b838ea552f5304d53a2518bc8ca4f7","_id":"@aminhanifm/issuesafe@0.1.1","_nodeVersion":"24.15.0","_npmVersion":"11.12.1","dist":{"integrity":"sha512-N6UbsLbzS4tbq33VOCl2nx2aZaVvyHWB1aZo0pkzxiUBMIregWYmr65xJeWcM10mJJboBUej/APif0riGVgyWg==","shasum":"07e7c1e20eae6649e7775c89e726b5661dcf2224","tarball":"https://registry.npmjs.org/@aminhanifm/issuesafe/-/issuesafe-0.1.1.tgz","fileCount":14,"unpackedSize":169634,"signatures":[{"keyid":"SHA256:DhQ8wR5APBvFHLF/+Tc+AYvPOdTpcIDqOhxsBHRwC7U","sig":"MEQCIEP6cu+u2zOeNivwcrB9hl9R+LUhY9jCQ/Yy6AwbUylEAiB96D6NuDtc7VkQhIVXIkQioLdqG0XS92/tMTDvZuXUeA=="}]},"_npmUser":{"name":"aminhanifm","email":"aminhanif24@gmail.com"},"directories":{},"maintainers":[{"name":"aminhanifm","email":"aminhanif24@gmail.com"}],"_npmOperationalInternal":{"host":"s3://npm-registry-packages-npm-production","tmp":"tmp/issuesafe_0.1.1_1784670369171_0.42811332641697963"},"_hasShrinkwrap":false}},"time":{"created":"2026-07-21T20:13:05.474Z","modified":"2026-07-21T21:46:09.435Z","0.1.0":"2026-07-21T20:13:05.795Z","0.1.1":"2026-07-21T21:46:09.301Z"},"bugs":{"url":"https://github.com/aminhanifm/IssueSafe/issues"},"author":{"name":"Amin Hanif"},"license":"MIT","homepage":"https://aminhanifm.github.io/projects/IssueSafe/","keywords":["privacy","log-redaction","developer-tools","cli","typescript","security","debugging"],"repository":{"type":"git","url":"git+https://github.com/aminhanifm/IssueSafe.git"},"description":"Sanitize developer logs and create shareable bug reports without uploading anything.","maintainers":[{"name":"aminhanifm","email":"aminhanif24@gmail.com"}],"readme":"# IssueSafe\n\n[![CI](https://github.com/aminhanifm/IssueSafe/actions/workflows/ci.yml/badge.svg)](https://github.com/aminhanifm/IssueSafe/actions/workflows/ci.yml)\n[![npm version](https://img.shields.io/npm/v/@aminhanifm/issuesafe.svg)](https://www.npmjs.com/package/@aminhanifm/issuesafe)\n[![MIT License](https://img.shields.io/badge/license-MIT-f4b95f.svg)](LICENSE)\n\n**[Try the interactive demo](https://aminhanifm.github.io/projects/IssueSafe/)** · [Security policy](SECURITY.md)\n\nIssueSafe sanitizes developer logs and creates shareable bug reports without uploading anything. Its deterministic, local-first workflow is deliberately reviewable:\n\n```text\nRaw log → detect common sensitive patterns → review redactions → export\n```\n\n> **IssueSafe detects common sensitive patterns. Review the result before sharing.**\n\n## Why IssueSafe exists\n\nLogs copied into issues, chats, support tickets, and AI assistants can contain authorization headers, credentials, identities, network addresses, or local usernames. Cleaning those logs by hand is slow and easy to get wrong. Fully automatic redaction is not a trustworthy guarantee either: a broad pattern can remove useful context, while an unfamiliar secret can pass through.\n\nIssueSafe occupies the useful middle. It finds a conservative set of common patterns, assigns stable placeholders, and gives you an explicit review step. It is not a replacement for Gitleaks or GitHub secret scanning, a compliance product, a hosted log platform, or an AI classifier.\n\n## Install\n\nIssueSafe requires Node.js 22 or newer and is published on npm as [`@aminhanifm/issuesafe`](https://www.npmjs.com/package/@aminhanifm/issuesafe).\n\n```bash\nnpm install --global @aminhanifm/issuesafe\nissuesafe --version\n```\n\nRun without a global install:\n\n```bash\nnpx @aminhanifm/issuesafe --version\n```\n\n## CLI\n\n```bash\n# Sanitized text to stdout\nissuesafe sanitize application.log\n\n# File output (existing files are protected)\nissuesafe sanitize application.log --output application.safe.log\n\n# Standard input and versioned JSON\ncat application.log | issuesafe sanitize --stdin --format json\n\n# Standard input to sanitized text\ncat application.log | issuesafe sanitize --stdin\n\n# Keep diagnostically useful IP addresses and emails\nissuesafe sanitize application.log --disable ip,email\n\n# GitHub-ready Markdown\nissuesafe issue application.log --title \"Application fails during startup\"\nissuesafe issue application.log --output bug-report.md\n\n# Deliberately replace an existing output\nissuesafe sanitize application.log --output application.safe.log --force\n```\n\nNormal output goes to `stdout`; errors go to `stderr`. Successful processing returns `0`. Invalid usage and processing failures return `2`. `--no-color`, `--help`, and `--version` are supported. IssueSafe never prints the sensitive input as part of an error message.\n\n## Browser workflow\n\nThe [static browser application](https://aminhanifm.github.io/projects/IssueSafe/) uses the same framework-independent engine as the CLI.\n\n1. Paste a log, choose a synthetic scenario, or load a UTF-8 `.log`, `.txt`, or `.json` file up to 2 MiB.\n2. Compare original and sanitized views. Affected lines are highlighted without HTML injection.\n3. Keep or redact each finding, or toggle a whole category. IP findings can remain visible when they are useful for debugging.\n4. Copy or download a sanitized log or a GitHub-ready Markdown issue.\n5. Clear the input to discard all in-memory review state.\n\nThe application does not copy automatically. It does not write raw input to local storage, session storage, cookies, IndexedDB, URLs, or analytics. It makes no runtime network requests after the page loads.\n\n## Detection categories\n\n| Category             | Conservative detection                                                                          |\n| -------------------- | ----------------------------------------------------------------------------------------------- |\n| Authorization        | Bearer, Basic, API-key-style, proxy authorization, and common API-key headers                   |\n| JWT                  | Three-part JWT-shaped values                                                                    |\n| Private keys         | Complete PEM-style private-key blocks                                                           |\n| Cookies and sessions | `Cookie`, `Set-Cookie`, and common session assignments                                          |\n| URL parameters       | `token`, `access_token`, `api_key`, `key`, `secret`, `password`, `session`, `signature`, `auth` |\n| Email                | Conventional email-address shapes                                                               |\n| IP addresses         | Valid IPv4 and common IPv6 shapes; category can be disabled                                     |\n| Home paths           | Username portion of `C:\\Users\\…`, `/Users/…`, and `/home/…`                                     |\n| Credentials          | Common assignments and credentials embedded in supported database URLs                          |\n\n### Before and after\n\n```text\nAuthorization: Bearer fake_documentation_token\nrequester: developer@example.invalid\nGET https://api.example.invalid/orders?access_token=synthetic_only\n```\n\n```text\nAuthorization: Bearer [TOKEN_1]\nrequester: [EMAIL_1]\nGET https://api.example.invalid/orders?access_token=[TOKEN_2]\n```\n\nRepeated values receive the same in-memory placeholder during one analysis. Different values in the same placeholder family increment deterministically. The private mapping resets for every analysis and never appears in exported results.\n\n## Security and privacy guarantees\n\n- Browser processing is local and the hosted application has no backend.\n- Raw logs are not uploaded, retained, or placed in browser storage.\n- The core engine has no React, browser, or Node dependency.\n- The versioned public result never includes original matched values.\n- Overlap resolution is explicit and deterministic: private-key blocks outrank their contents; authorization and cookie detections outrank generic matches.\n- User-provided content is rendered as text, not injected as HTML.\n- Samples and tests use synthetic values, `example.invalid` domains, and documentation address ranges.\n\nThese are implementation properties, not a claim that output is completely safe. A compromised credential must be revoked or rotated; redacting it from a report does not remediate exposure. Read the [threat model and reporting policy](SECURITY.md).\n\n## Honest limitations\n\nPattern matching has false positives and false negatives. In particular:\n\n- Custom credential names, opaque vendor formats, secrets split across lines, and transformed or encrypted values may not be detected.\n- An arbitrary JWT-shaped value, IP address, email-like identifier, or home-path segment may be benign.\n- Cookie headers are redacted as a unit, which can remove non-sensitive cookie debugging context.\n- IPv6 recognition is intentionally conservative and does not cover every valid presentation.\n- File decoding in the browser accepts UTF-8 only; the CLI expects UTF-8 text.\n- IssueSafe does not scan source repositories, history, binary files, archives, or remote systems.\n\nAlways review surrounding text and rotate exposed credentials.\n\n## Package API\n\n```ts\nimport {\n  analyzeLog,\n  applyRedactions,\n  createIssueReport,\n  type AnalysisResult,\n  type Finding,\n} from \"@aminhanifm/issuesafe\";\n\nconst result: AnalysisResult = analyzeLog(rawLog, {\n  disabledCategories: [\"ip\"],\n});\n\nconst selected: Finding[] = result.findings.map((finding) => ({\n  ...finding,\n  enabled: finding.category !== \"email\",\n}));\n\nconst sanitized = applyRedactions(rawLog, selected);\nconst markdown = createIssueReport(\n  { ...result, sanitizedText: sanitized, findings: selected },\n  { title: \"Application fails during startup\", reviewed: true },\n);\n```\n\nThe `AnalysisResult` schema is versioned separately from the package. Within `0.x`, documented exported types and behavior are treated as stable but may receive breaking changes in a minor release with changelog notice. Public findings include location, category, detector ID, placeholder, and enabled state—never the matched value.\n\n## Architecture\n\n```text\nsrc/core/          deterministic detectors, overlap resolution, reporting\nsrc/cli/           Node-only file/stdin/stdout adapter using Commander\ndemo/src/          React review interface; imports the same core directly\ntest/              detector, redaction, reporting, and CLI tests\ndocs/              release and design artifacts\n```\n\nThe core package depends only on language primitives. Detectors produce private candidates; priority-based overlap resolution chooses non-overlapping ranges; placeholders are assigned after resolution; the public result is then built and sanitized.\n\n## Development\n\n```bash\nnpm ci\nnpm run dev\nnpm run format\nnpm run lint\nnpm run typecheck\nnpm test\nnpm run test:coverage\nnpm run build\nnpm run build:demo\nnpm run pack:dry-run\nnpm run verify:package\nnpm run check\n```\n\n`verify:package` creates a tarball in a temporary directory, installs it as a consumer, and exercises the installed CLI. CI runs on Node.js 22 and 24 on Ubuntu and Windows.\n\n## Contributing\n\nFocused issues and pull requests are welcome. Read [CONTRIBUTING.md](CONTRIBUTING.md), the [Code of Conduct](CODE_OF_CONDUCT.md), and [SECURITY.md](SECURITY.md) before submitting. Never include real credentials or private logs in fixtures, issues, or screenshots.\n\n## Roadmap\n\n- Additional conservative vendor-specific token shapes backed by public documentation\n- Import/export of redaction decisions without original values\n- Expanded accessibility and cross-browser regression coverage\n\nIssueSafe is available under the [MIT License](LICENSE).\n","readmeFilename":"README.md"}