From efcdf60a4fc50e9bfd35790e5aac9249a84b2106 Mon Sep 17 00:00:00 2001 From: FranRom <32134460+FranRom@users.noreply.github.com> Date: Mon, 18 May 2026 11:39:29 +0200 Subject: [PATCH] chore: add MIT license and security policy MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit P0 work to make the repo open-source ready: - LICENSE: MIT, 2026 FranRom - package.json: declare "license": "MIT" so GitHub auto-detects + shows the badge - SECURITY.md: coordinated disclosure policy with in-scope (URL allowlist, MCP path traversal, apply-queue races, CV parser, install scripts) / out-of-scope (upstream sources, LLM CLIs, exposing the local UI publicly) sections - README.md: replace "Personal project — no license. Don't redistribute." with an MIT pointer - CONTRIBUTING.md: replace "The repo has no open-source license" line with the MIT pointer --- CONTRIBUTING.md | 2 +- LICENSE | 21 ++++++++++++++++++++ README.md | 2 +- SECURITY.md | 52 +++++++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + 5 files changed, 76 insertions(+), 2 deletions(-) create mode 100644 LICENSE create mode 100644 SECURITY.md diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index bd30495..86535b4 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,7 +7,7 @@ This repo is a local-first, config-driven job aggregator. Contributions should p - Read [`README.md`](./README.md) for the product flow and [`AGENTS.md`](./AGENTS.md) for the detailed implementation rules. - Use Node 22 and pnpm 10. - Keep changes small and focused. Do not mix personal profile tuning, generated job output, and code changes unless the PR explicitly needs all of them. -- The repo has no open-source license. These notes are a contribution workflow, not a redistribution grant. +- The repo is MIT-licensed (see [`LICENSE`](./LICENSE)). Contributions are accepted under the same terms. ## Local Setup diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..841f312 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2026 FranRom + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/README.md b/README.md index c075ef7..cb7ee26 100644 --- a/README.md +++ b/README.md @@ -928,4 +928,4 @@ These are currently affecting the data quality — they're documented here so th ## License -Personal project — no license. Don't redistribute. +MIT — see [`LICENSE`](./LICENSE). Fork it, run it locally, tune it to your stack. The only ask: keep the copyright notice in copies you redistribute. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..fdfb9ee --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,52 @@ +# Security policy + +`pupila` is a local-first tool — it runs entirely on your machine, has no hosted backend, and the UI is bound to `127.0.0.1` only. That said, the code touches user data (CV, application history, candidate brief) and parses HTML/JSON/RSS from third-party sources, so a few classes of issue do matter. + +## Supported versions + +Only the latest commit on `main` is supported. There are no tagged releases or LTS branches — pull the latest before reporting. + +## Reporting a vulnerability + +For most issues, open a GitHub issue at **https://github.com/FranRom/pupila/issues** with a `[security]` prefix in the title. Since pupila is a local-first tool with no hosted backend, there's no production deployment to coordinate around — public discussion is fine for the vast majority of reports. + +For coordinated disclosure (when public discussion before a fix would be genuinely risky — e.g. an active exploitation pattern not obvious from reading the source), use GitHub's **private vulnerability reporting** at **https://github.com/FranRom/pupila/security/advisories/new**. The filing stays private until a fix is published. + +Either way, include: + +- A description of the issue and the impact (data exfiltration, code execution, privilege escalation, etc.). +- Steps to reproduce — ideally a minimal patch / repo state that triggers the behavior. +- Any suggested remediation. + +Solo-maintained project — responses are best-effort, not a contractual SLA. I aim to acknowledge within 7 days and ship a fix (or a written rationale for why it's not actionable) within 30 days. + +## In scope + +- The aggregator pipeline (`src/`) — fetchers, normalizers, filters, dedup, render, feed. +- The MCP server (`src/mcp/`) — tool surface, JSON-RPC handling, path traversal, command injection. +- The local UI (`ui/`) and its Vite dev-server middleware (`/api/*` endpoints). +- The apply-worker and apply-queue lock semantics (`src/lib/apply-queue.ts`, `scripts/apply-worker.ts`). +- The CV parsing path (`mammoth` / `pdfjs-dist` integration in `src/lib/cv-parser.ts`). +- Install scripts (`scripts/install-launchd.sh`, `install-cron.sh`, `install-mcp.sh`). + +Examples of in-scope issues: + +- An upstream source returning a `javascript:` / `data:` / `file:` URL that escapes the `isSafeUrl` gate. +- HTML-attribute escaping bypass in `JOBS.md` or the RSS feed. +- A malicious LLM-CLI response that triggers path traversal in `data/applications/.md` writes. +- Apply-queue lock race conditions that drop or duplicate work. +- A malformed CV that crashes or hangs the parser unrecoverably. +- MCP tool-input validation gaps that let a client read or write outside `data/` / `config/`. + +## Out of scope + +- Vulnerabilities in upstream sources themselves (Ashby, Greenhouse, Lever, RSS feeds, etc.). Report to the upstream operator. +- Vulnerabilities in the local LLM CLIs (`claude`, `codex`, `gemini`, `opencode`). Report to the respective vendor. +- Issues that require the attacker to already have local code execution on your machine — at that point they own everything anyway. +- Exposing the UI publicly. The dev server binds to `127.0.0.1:5173` by design; running it on a public interface is a configuration mistake, not a vulnerability. +- Committing `config/applied.json` or `config/candidate-brief.md` to a public fork. Both are gitignored; the user has to explicitly opt in to track them. +- Dependency CVEs already flagged by `pnpm audit` in CI — those are tracked in the open and Dependabot PRs. + +## Hall of fame + +Reporters who responsibly disclose actionable issues will be credited here (with their consent). Mention it in your issue or advisory if you'd like to be named. diff --git a/package.json b/package.json index f6d94dd..8f41e80 100644 --- a/package.json +++ b/package.json @@ -4,6 +4,7 @@ "private": true, "type": "module", "description": "Config-driven local-first daily job aggregator.", + "license": "MIT", "engines": { "node": ">=22 <23", "pnpm": ">=11 <12"