diff --git a/AGENTS.md b/AGENTS.md index ba224a8..3efdc88 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -16,8 +16,7 @@ Before implementing, review: safe-formdata is a **boundary-focused FormData parser**. -Its sole responsibility is to establish a strict, security-oriented boundary -between untrusted FormData input and application logic. +Its sole responsibility is maintaining a strict parsing boundary between untrusted FormData and application logic. This document defines the non-negotiable rules for implementation and review. @@ -97,7 +96,7 @@ This is non-optional and part of the boundary definition. ## Key validation criteria -To maintain a predictable boundary, keys must meet the following criteria. Failure to do so results in an `invalid_key` issue. +Keys failing any of the following result in an `invalid_key` issue: - **Non-empty**: A key must have a length > 0. - Note: Keys consisting only of whitespace characters are considered valid as they satisfy the length requirement and preserve the "opaque strings" principle. @@ -122,7 +121,7 @@ No additional IssueCode may be introduced without a major version bump. - `key` must be the original FormData key that caused the issue, reported as-is without interpretation. - Issues are informational, not exceptions. -Note: In v1.0+, additional fields such as `message: string` and `meta?: Record` may be considered for enhanced error reporting. +Note: In v1.0+, additional fields (e.g., `message`, `meta`) may be added for richer error reporting. --- @@ -181,7 +180,7 @@ export type IssueCode = "invalid_key" | "forbidden_key" | "duplicate_key"; **Type documentation:** -All type definitions include comprehensive JSDoc comments for IDE integration. See: +All public types include JSDoc comments for IDE integration. See: - `src/types/ParseResult.ts` - Discriminated union with type narrowing examples - `src/types/ParseIssue.ts` - Issue structure and property explanations diff --git a/CLAUDE.md b/CLAUDE.md index ce160f5..b675eec 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -23,7 +23,7 @@ Review this code against boundary-validator rules ## Usage Examples -The `examples/` directory contains comprehensive usage examples: +The `examples/` directory contains usage examples: - `00-basic.ts` - Basic parsing and type narrowing - `01-file-upload.ts` - File handling with type guards diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 30ae2bd..e8157b0 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -2,14 +2,10 @@ Thank you for your interest in contributing to safe-formdata! -This document provides guidelines for contributing to this boundary-focused FormData parser. - --- ## Before You Start -**Please read these documents carefully.** - 1. **README.md**: Understand the design principles and what safe-formdata is (and isn't) 2. **AGENTS.md**: Review the non-negotiable implementation rules 3. **Design decisions (Why not?)**: Understand why certain features are intentionally excluded @@ -47,8 +43,6 @@ bun run test:watch # Watch mode for testing ## Project Philosophy -safe-formdata establishes a **strict boundary** between untrusted FormData input and application logic. - ### Core Principles (from README.md) - 🧱 **Keys are opaque**: Never interpret key naming conventions @@ -135,7 +129,7 @@ Before submitting a PR: ### PR Description -Include the following. +Include the following: 1. **Problem**: What issue does this solve? 2. **Solution**: How does this maintain the boundary? @@ -144,7 +138,7 @@ Include the following. ### Review Process -PRs will be evaluated against the following. +PRs are evaluated against: 1. **Alignment with design principles** (README.md) 2. **Compliance with technical rules** (AGENTS.md) diff --git a/README.md b/README.md index 9c62a67..4e93862 100644 --- a/README.md +++ b/README.md @@ -2,14 +2,14 @@ **The strict trust boundary for FormData.** +safe-formdata is a **security-focused** FormData parser. +It enforces rules on keys and forbids structural inference by design. + [![Ask DeepWiki](https://deepwiki.com/badge.svg)](https://deepwiki.com/roottool/safe-formdata) [![npm version](https://img.shields.io/npm/v/safe-formdata)](https://www.npmjs.com/package/safe-formdata) [![CI](https://github.com/roottool/safe-formdata/actions/workflows/ci.yml/badge.svg)](https://github.com/roottool/safe-formdata/actions/workflows/ci.yml) [![codecov](https://codecov.io/gh/roottool/safe-formdata/graph/badge.svg)](https://codecov.io/gh/roottool/safe-formdata) -safe-formdata is a **security-focused** parser that establishes a predictable boundary between untrusted input and application logic. -It enforces strict rules on keys and forbids structural inference by design. - ## Table of Contents - [safe-formdata](#safe-formdata) @@ -76,10 +76,7 @@ Anything beyond this boundary — including value validation, schema enforcement framework conventions, authentication, or denial-of-service protection — is **out of scope** and must be handled by the application. -📘 **Authoritative security guarantees, assumptions, and reporting policy:** -See [SECURITY.md](./SECURITY.md) - -Security decisions and issue triage are based on the definitions in SECURITY.md. +Security guarantees, assumptions, and reporting policy: [SECURITY.md](./SECURITY.md) --- @@ -128,7 +125,7 @@ their interpretation necessarily implies structure Defining or inferring such structure is outside the scope of safe-formdata. -safe-formdata establishes a strict, non-inferential boundary: +safe-formdata enforces a strict rule: each key must map to exactly one value (`string` or `File`), or the input is rejected. @@ -156,7 +153,7 @@ Validation and typing belong beyond it. ## Installation -Install safe-formdata using your preferred package manager: +Install: ```bash # npm @@ -201,9 +198,8 @@ if (result.data !== null) { - All values are `string | File` - no automatic type conversion - Use `data !== null` to check for success and narrow the type -- Security boundaries are enforced from the start -For complete examples including file uploads and validation patterns, see the [examples/](./examples) directory. +See [examples/](./examples) for file upload handling and more. --- @@ -254,7 +250,7 @@ No inference or convenience features will be added within v0.x. ## Contributing -Contributions are welcome! Please see: +See: - [CONTRIBUTING.md](CONTRIBUTING.md) - Contributor guide - [docs/PUBLISHING.md](docs/PUBLISHING.md) - Publishing guide (for maintainers) diff --git a/SECURITY.md b/SECURITY.md index 8bc5aac..21fd157 100644 --- a/SECURITY.md +++ b/SECURITY.md @@ -1,7 +1,5 @@ # Security Policy -safe-formdata is a **boundary-focused FormData parser** designed with security as a core principle. - This document defines: - How to report security issues responsibly @@ -9,14 +7,13 @@ This document defines: - The security guarantees and assumptions of this library - How security-related issues are evaluated and handled -This policy serves as the **authoritative reference** for security-related decisions, -including issue triage and closure. +This policy governs security issue triage and closure decisions. --- ## Supported Versions -**Only the latest release receives security updates.** +Only the latest release receives security updates. Security fixes are not backported. Users must upgrade to the latest version to receive security patches. @@ -30,7 +27,7 @@ and **public security discussion**. ### Private (Security Advisory) -Use **GitHub Security Advisories** for the following. +Use **GitHub Security Advisories** for: - Reproducible vulnerabilities - Exploit techniques or payloads @@ -42,7 +39,7 @@ Use **GitHub Security Advisories** for the following. ### Public Issue -Public issues are appropriate only for the following. +Public issues are appropriate for: - **Design-level security questions** - **Non-sensitive security concerns** @@ -102,9 +99,7 @@ The following are **not** considered security vulnerabilities: - **API misuse** - Incorrect usage by consumers (e.g., ignoring `issues`) -If an issue falls under these categories, -it will be **closed without action**, even if it has security implications -at the application level. +If an issue falls under these categories, it will be **closed without action**, even if it has security implications at the application level. --- @@ -149,7 +144,7 @@ safe-formdata **assumes**: ## Disclosure Policy -Security reports are handled as follows. +Security reports are handled as follows: 1. **Review** - Issues are evaluated against the security scope defined above diff --git a/skills/README.md b/skills/README.md index f8bc3f9..22b31f3 100644 --- a/skills/README.md +++ b/skills/README.md @@ -4,7 +4,7 @@ This directory contains **Agent Skills** specific to the safe-formdata project. ## What are Agent Skills? -Agent Skills are structured knowledge packages that agents like Claude Code can efficiently reference. Based on the implementation rules in AGENTS.md, they provide the following. +Agent Skills are structured knowledge packages for agents like Claude Code. Based on AGENTS.md, they provide: - **Automatic triggering**: Activates automatically during PR creation and code review - **Progressive disclosure**: Loads only necessary information incrementally diff --git a/src/issues/createIssue.ts b/src/issues/createIssue.ts index add534e..68696b3 100644 --- a/src/issues/createIssue.ts +++ b/src/issues/createIssue.ts @@ -1,18 +1,7 @@ import type { IssueCode } from "#types/IssueCode"; import type { ParseIssue } from "#types/ParseIssue"; -/** - * Creates a ParseIssue with the specified code and key. - * - * This is an internal utility function for generating structured issue reports - * during FormData parsing. - * - * @param code - The type of issue (invalid_key, forbidden_key, or duplicate_key) - * @param key - The FormData key that caused the issue - * @returns A ParseIssue object ready to be added to the issues array - * - * @internal - */ +/** @internal */ export function createIssue(code: IssueCode, key: string): ParseIssue { return { code, key }; } diff --git a/src/issues/forbiddenKeys.ts b/src/issues/forbiddenKeys.ts index a228e54..9c8277a 100644 --- a/src/issues/forbiddenKeys.ts +++ b/src/issues/forbiddenKeys.ts @@ -4,14 +4,10 @@ * These keys are reserved properties on `Object.prototype` and must never * be allowed in parsed FormData, regardless of their values or context. * - * The forbidden keys are the following. * - `__proto__`: Legacy prototype accessor * - `prototype`: Function prototype property * - `constructor`: Object constructor reference * - * Any FormData entry containing these keys will trigger a `forbidden_key` issue, - * causing the parse operation to fail with `data: null`. - * * @see {@link https://github.com/roottool/safe-formdata/blob/main/AGENTS.md#prototype-safety AGENTS.md > Security rules > Prototype safety} */ export const FORBIDDEN_KEYS: ReadonlySet = new Set([ diff --git a/src/parse.ts b/src/parse.ts index 620b821..54433a2 100644 --- a/src/parse.ts +++ b/src/parse.ts @@ -4,16 +4,14 @@ import type { ParseIssue } from "#types/ParseIssue"; import type { ParseResult } from "#types/ParseResult"; /** - * Parses FormData into a flat JavaScript object with strict boundary enforcement. + * Parses FormData into a flat JavaScript object. * - * This function establishes a security-focused boundary between untrusted FormData input - * and application logic by: - * - Detecting duplicate, forbidden, and invalid keys - * - Treating keys as opaque strings (no structural inference) - * - Returning null data if any issues are detected (no partial success) + * Fails completely if any entry violates the rules below — no partial success: + * - Duplicate, forbidden, and invalid keys are rejected + * - Keys are treated as opaque strings (no structural inference) * * @param formData - The FormData instance to parse - * @returns ParseResult containing either parsed data or issues (never both) + * @returns ParseResult containing either parsed data or issues, never both * * @example * ```ts diff --git a/src/types/IssueCode.ts b/src/types/IssueCode.ts index 68f0ce2..555dbb9 100644 --- a/src/types/IssueCode.ts +++ b/src/types/IssueCode.ts @@ -1,8 +1,6 @@ /** * Type of validation issue detected during FormData parsing. * - * All issue codes represent security boundaries enforced by safe-formdata: - * * - **`invalid_key`**: Key is empty or not a string. * Prevents ambiguous or unrepresentable keys from entering application logic. * diff --git a/src/types/ParseResult.ts b/src/types/ParseResult.ts index f4b86c3..9aeeb36 100644 --- a/src/types/ParseResult.ts +++ b/src/types/ParseResult.ts @@ -3,7 +3,7 @@ import type { ParseIssue } from "#types/ParseIssue"; /** * Result of parsing FormData with {@link parse}. * - * This is a discriminated union type. Use `data !== null` to narrow the type: + * Use `data !== null` to narrow the type: * - `data !== null` → Success: parsed data available, issues is empty array * - `data === null` → Failure: validation issues occurred * @@ -51,7 +51,7 @@ export type ParseResult = data: Record; /** - * Empty array when parsing succeeds. + * Always `[]` on success — kept for consistent destructuring alongside the failure branch. */ issues: []; } @@ -66,8 +66,6 @@ export type ParseResult = /** * Non-empty array of validation issues that prevented successful parsing. * - * Always contains at least one issue when `data` is `null`. - * * Possible issue codes: * - `invalid_key`: Key is empty or not a string * - `forbidden_key`: Key is a forbidden prototype property