diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..bb73cfb --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,150 @@ +# Contributing to Obscura + +Thanks for your interest in Obscura. This guide covers how to build, test, and +submit changes. For the deeper, non-obvious engine details (architecture, +gotchas, robustness invariants), read [AGENTS.md](AGENTS.md) first; this file +does not repeat it. + +## Code of conduct + +Be respectful and constructive. We want Obscura to be a welcoming project, so +keep discussion focused on the work and assume good faith. Harassment or abuse +is not tolerated. + +## Before you start + +For anything beyond a minor documentation fix, **please open an issue first** (or +comment on an existing one) and say you intend to work on it. This lets us give +early feedback and avoids two people building the same thing or a PR that does +not fit the project's direction. + +A few notes to keep the project maintainable: + +- **Link an issue.** PRs without a linked issue or prior discussion may be + closed, except for small doc fixes. +- **Human oversight required.** AI-assisted contributions are fine, but + low-quality or unreviewed agent output will be closed. Understand and test + what you submit. +- New to the codebase? Look for issues labeled `good first issue`. + +## Building + +```bash +cargo build --release # binary at ./target/release/obscura +``` + +- The first build compiles V8 from source: roughly 5 minutes and a few GB of + disk. Incremental builds are seconds. +- Iterating on one crate? Scope it: `cargo build -p obscura-cli`. +- **Stealth** (`--features stealth`) pulls in BoringSSL through CMake, so `cmake` + must be installed. The default build uses rustls and needs neither CMake nor + OpenSSL. +- If the vendored OpenSSL build hits an AVX-512 assembler error on your host, + build with `OPENSSL_NO_VENDOR=1`. + +## Testing + +Run tests with **`cargo nextest`, not `cargo test`**: + +```bash +cargo nextest run --workspace # or -p while iterating +``` + +`cargo test` runs the whole test binary in one process, but the engine holds a +single V8 isolate per process, so the runtime tests fail under it. `nextest` +runs each test in its own process, which is the only supported way. + +The authoritative behavioral gate is the **obstacle course** in the companion +repo [`obscura-benchmark`](https://github.com/h4ckf0r0day/obscura-benchmark) +(33 capability and speed stages, must stay 33/33): + +```bash +OBSCURA_BIN=./target/release/obscura python3 obstacle-course/run.py --runs 1 --warmup 0 +``` + +It serves local fixtures, so it is deterministic and offline. + +## Before you open a PR + +For any code change: + +1. `cargo build --release` (or `-p `) compiles clean. +2. `cargo nextest run` passes for the crates you touched. +3. The obstacle course still reports **33/33**. +4. **Performance is a hard constraint.** Obscura is roughly 12x faster and uses + about 6x less memory than headless Chrome on framework pages. Keep the native + Rust fast paths and add a JS fallback only for real spec edge cases. If your + change could affect performance, benchmark old vs new interleaved, min-of-N + (the noise floor is about plus or minus 10%). +5. For stealth changes, re-test with `--stealth`. A non-stealth binary does not + exercise the `wreq` path. + +Keep ops panic-safe: a panic in an op must degrade to a null result, never +unwind into V8's FFI frame. Do not remove the robustness guards described in +AGENTS.md (the V8 watchdog, the `tree.rs` reparenting guards, the CLI deadline). + +Do not bulk-run `cargo fmt`. The tree is not rustfmt-clean, so a blanket format +produces a large unrelated diff. Match the surrounding style in the files you +edit. Comments should explain non-obvious "why", not restate the code. + +## Commit messages + +Keep them short and factual: what changed and why. We use a lightweight +`type(scope): summary` style, matching the existing history: + +``` +fix(cdp): honor text selection on Backspace and typing + +Backspace trimmed the last character and typing always appended, ignoring +any selection. Both now respect a non-collapsed selection. + +Fixes #316. +``` + +- `type` is one of `fix`, `feat`, `docs`, `test`, `perf`, `chore`. The `scope` + is optional and lowercase (for example `cdp`, `js`, `net`, `stealth`, `cli`). +- No em dashes. Use commas, periods, or restructure the sentence. +- No AI-generated filler ("This commit improves...", "As an AI..."). +- Do not add `Co-Authored-By` lines or list yourself as a co-author. + +## Pull requests + +- All submissions are reviewed; a maintainer merges after approval. +- Keep the diff small and readable. One logical change per PR. Split large + contributions into several PRs. +- Reference the issue the PR closes, and say how you verified it (the test or + repro that now passes). + +## Reporting bugs + +Open an issue with enough detail to reproduce: + +- The obscura version or commit, plus OS and architecture. +- A repro: a URL, an `--eval` snippet, or a short CDP sequence. +- What you expected and what actually happened. +- If it is a rendering or compatibility issue, whether headless Chrome behaves + the same. Anti-bot, CAPTCHA, and login walls block headless Chrome too from a + datacenter IP, so those are not engine bugs. + +Multi-statement `--eval` that starts with `const` returns `null` (V8 gives +`const` an empty completion value). Wrap repro snippets in an IIFE: +`(function(){ ...; return result; })()`. + +**Security issues:** do not open a public issue. See [SECURITY.md](SECURITY.md) +for private reporting. + +## Scope and direction + +Obscura targets web scraping and AI-agent automation, and is heading toward a +hosted cloud scraping service. The priorities are real-world render success and +robustness (no crashes or hangs). Conformance and new Web APIs are welcome when +they do not regress performance or stability. + +The stealth features are privacy-first anti-fingerprinting: they present a +normal, consistent browser identity so ordinary automation is not singled out. +Contributions that add detection-evasion for abusive purposes are out of scope. + +## License + +By contributing, you agree that your contributions are licensed under the +[Apache License 2.0](LICENSE), the same license as the project. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000..c4cdc24 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,109 @@ +# Security Policy + +The Obscura project takes security seriously. Obscura runs real, untrusted +JavaScript from arbitrary web pages through V8, so we appreciate your efforts to +responsibly disclose what you find and will work with you to address it. + +## Reporting a vulnerability + +**Please do not report security issues through public GitHub issues, pull +requests, or discussions.** + +Report a vulnerability privately through GitHub: go to the repository's +**Security** tab and click [**Report a vulnerability**](https://github.com/h4ckf0r0day/obscura/security/advisories/new) +to open a private advisory. + +If you cannot use GitHub advisories, email **hello@obscura.sh** with "security" +in the subject line. + +### What to include + +To help us triage quickly, please provide as much of the following as you can: + +- Type of issue (SSRF, hang or crash / denial of service, memory safety, + cross-session data exposure, etc.). +- The obscura version or commit, plus OS and architecture. +- The location of the affected code (file path and commit, or a direct link). +- Any special configuration or flags required to reproduce. +- Step-by-step instructions: a page, `--eval` snippet, or CDP sequence that + triggers it. +- Proof-of-concept code if you have it, and the impact you think it has. + +## Our response + +We will send a response indicating the next steps in handling your report, +normally within 3 business days. We will keep you informed of progress toward a +fix, and may ask for additional information. We practice coordinated disclosure: +please give us a reasonable window to ship a fix before any public writeup, and +we will credit you in the advisory unless you ask us not to. + +If you do not receive an acknowledgement within 6 business days, please follow +up by email to make sure we received the report. + +## Scope + +Obscura is a powerful tool for browser automation, scraping, and inspection. It +is the responsibility of the calling code and the operator to use it safely. The +security boundaries Obscura is meant to hold, and which are in scope: + +- **Egress / SSRF control.** Page content reaching loopback, RFC 1918, or + link-local addresses without `--allow-private-network` being set. +- **Availability.** A page, script, or DOM structure that defeats the V8 + termination watchdog, the CLI hard deadline, or the panic guards and so hangs + or aborts the process. +- **Memory safety** in Obscura's own `unsafe` Rust or in an op that bridges JS + to Rust. +- **Process and data integrity.** A page that escapes the intended op surface, + corrupts another page's state, or reads data across origins or sessions it + should not (cookies, storage, response bodies). +- **TLS / identity correctness** issues that weaken or misrepresent a connection + in a way the user did not request. + +The following are **not** vulnerabilities. We welcome feedback on them as +feature requests, but they will not be treated as security issues: + +- **Stealth / anti-fingerprinting behavior.** Presenting a normal, consistent + browser fingerprint is the intended, privacy-first design of stealth mode. + Requests to add detection-evasion for abusive purposes are out of scope. +- **Anything behind an explicit opt-in,** such as reaching a private address + when `--allow-private-network` (or `OBSCURA_ALLOW_PRIVATE_NETWORK=1`) is set, + or behavior that requires local access to the machine running Obscura. +- **Resource use from a page you chose to load** that stays within the watchdog + and deadline limits. Slow pages are not a vulnerability. +- **Findings against the companion benchmark repo fixtures** rather than the + engine itself. + +## Third-party dependencies + +Report vulnerabilities in third-party crates to their respective maintainers (or +the [RustSec advisory database](https://rustsec.org/)). The workspace is gated +by `cargo deny` via `deny.toml`. If a dependency advisory affects Obscura's own +behavior, let us know so we can pin or patch. + +## Security model and operator responsibilities + +Obscura executes untrusted page JavaScript **in process** through V8. Its +in-process hardening reduces blast radius but is not a substitute for operating +system isolation: + +- The **V8 termination watchdog** terminates the isolate from a separate thread + when synchronous script work overruns, because `tokio` timeouts only cancel at + await points. +- The **CLI process-level hard deadline** is an absolute backstop for a hang + inside a Rust op that neither `tokio` nor `terminate_execution` can interrupt. +- **Panic safety:** ops are wrapped so a panic degrades to a null result instead + of aborting the process inside V8's FFI frame; `panic = "unwind"` is pinned in + the release profile. +- The **default network egress policy** blocks private and loopback ranges. + +These measures protect availability and limit egress. They do **not** claim to +contain a hostile page that achieves native code execution through a V8 exploit. +If you run Obscura against untrusted or adversarial input at scale, run it under +OS-level isolation (a container or VM) with a restricted network, the same way +you would run headless Chrome. Per-user container isolation is planned for the +hosted service so that one session cannot affect another. + +## Supported versions + +Security fixes land on `main` and ship in the next release. Please test reports +against the latest release or `main`.