Initial Commit
This commit is contained in:
@@ -0,0 +1,38 @@
|
||||
# OpenSpec Change: enterprise-password-formats
|
||||
|
||||
- **Change ID**: enterprise-password-formats
|
||||
- **Package**: `@suaveplan/password-formats`
|
||||
- **Category**: universal
|
||||
- **Target path**: `universal/auth/password-formats`
|
||||
- **Status**: PROPOSED
|
||||
- **Date**: 2026-04-19
|
||||
- **Reference spec**: `/mnt/s/web/suaveplan/enterprise/password-formats.md`
|
||||
|
||||
## Summary
|
||||
Universal import/export layer for common password-manager export formats — Apple Passwords CSV, Bitwarden JSON, Chrome CSV, KeePass XML, LastPass CSV, 1Password `.1pux` archive and CSV. Produces a normalised `PasswordEntry[]` plus reverse CSV export.
|
||||
|
||||
## Current-state audit (genesis)
|
||||
Package does not exist yet — fresh build.
|
||||
|
||||
## Dependencies
|
||||
- Workspace: none (leaf)
|
||||
- External (via catalog): `zod`, `papaparse`, `fast-xml-parser`, `fflate` → appropriate catalogs; `tslib`; `@opentelemetry/api`
|
||||
- Dev (via catalog): `vitest`, `@vitest/coverage-istanbul`, `fast-check`, `mitata`
|
||||
|
||||
## Preserved public surface
|
||||
- `detect(input): PasswordFormat` — sniff format from filename/content
|
||||
- `parse(input, format?): Promise<PasswordEntry[]>` — unified parse entry point
|
||||
- `validate(entries): ValidationResult` — structural validation
|
||||
- `exportToCsv(entries): string`
|
||||
- Format-specific parsers: `parseApplePasswordsCsv`, `parseBitwardenJson`, `parseChromeCsv`, `parseKeePassXml`, `parseLastPassCsv`, `parseOnePassword1Pux`, `parseOnePasswordCsv`
|
||||
- Types: `PasswordEntry`, `PasswordFormat`, `ValidationResult`, `ParseOptions`
|
||||
|
||||
## New genesis additions
|
||||
- Codes: `PASSWORD_FORMATS.UNKNOWN_FORMAT`, `PASSWORD_FORMATS.PARSE_ERROR`, `PASSWORD_FORMATS.VALIDATION_FAILED`, `PASSWORD_FORMATS.ENCRYPTED_INPUT`.
|
||||
- Zod schema for `PasswordEntry` (+ per-format raw-row schemas).
|
||||
- OTel histogram `password_formats.parse.duration_ms{format}`; counter `password_formats.entries.total{format}`.
|
||||
- Property tests: CSV round-trip (`parse(exportToCsv(entries))` ≈ `entries` after normalisation).
|
||||
|
||||
## Impact
|
||||
- Adds one new package: `universal/auth/password-formats`
|
||||
- Adds one new spec capability: `password-formats`
|
||||
@@ -0,0 +1,27 @@
|
||||
# Capability Spec: password-formats
|
||||
|
||||
**Package**: `@suaveplan/password-formats`
|
||||
**Version**: 0.0.0 (genesis)
|
||||
**Status**: ADDED
|
||||
|
||||
---
|
||||
|
||||
## ADDED Requirements
|
||||
|
||||
### PF-01 — Normalised entry shape
|
||||
`PasswordEntry` MUST be `{ id, title, username?, password, url?, urls?: string[], notes?, otp?, createdAt?, updatedAt?, folder?, tags?: string[], fields?: Record<string, string>, sourceFormat: PasswordFormat }`. Every parser MUST produce this shape. The schema MUST be enforced via `PasswordEntrySchema.parse`.
|
||||
|
||||
### PF-02 — Format detection
|
||||
`detect(input)` MUST return one of `'apple-passwords' | 'bitwarden-json' | 'chrome' | 'keepass-xml' | 'lastpass' | '1password-csv' | '1password-1pux' | 'unknown'`. Detection MUST use a combination of filename heuristics (when provided) and content sniffing (first-line CSV header, XML root element, JSON shape, ZIP magic bytes). Unknown inputs MUST return `'unknown'`, not throw.
|
||||
|
||||
### PF-03 — Parser dispatch
|
||||
`parse(input, format?)` MUST call `detect` when `format` is absent. Unknown formats MUST throw `PASSWORD_FORMATS.UNKNOWN_FORMAT`. Encrypted inputs (Bitwarden `encrypted: true`, encrypted `.1pux`) MUST throw `PASSWORD_FORMATS.ENCRYPTED_INPUT` with actionable context.
|
||||
|
||||
### PF-04 — CSV round-trip
|
||||
`exportToCsv(parse(x))` MUST be a stable fixed point for CSV-sourced inputs ignoring field ordering and optional fields; round-trip property tests MUST verify this on generated entries.
|
||||
|
||||
### PF-05 — Validation
|
||||
`validate(entries)` MUST return `{ ok, errors: Array<{ index, field, message }> }`. Validation MUST reject entries missing `password` or `title`.
|
||||
|
||||
### PF-06 — Observability
|
||||
Parsing MUST record `password_formats.parse.duration_ms` histogram (label `format`) and `password_formats.entries.total` counter (label `format`). No password values MUST appear in OTel attributes.
|
||||
@@ -0,0 +1,37 @@
|
||||
# Tasks: enterprise-password-formats
|
||||
|
||||
## 1. Scaffold
|
||||
- [x] 1.1 Create `universal/auth/password-formats/`; 100/100/100/100.
|
||||
- [x] 1.2 Guard tests; CLAUDE/README/FOLDERS updates.
|
||||
|
||||
## 2. Errors + schemas
|
||||
- [x] 2.1 `src/errors/password-formats-error.ts` — codes.
|
||||
- [x] 2.2 Zod schemas: `PasswordEntrySchema`, per-format raw-row schemas.
|
||||
|
||||
## 3. Core
|
||||
- [x] 3.1 `src/core/detector/format-detector.ts` — `detect`.
|
||||
- [x] 3.2 Dispatcher `src/core/parse/parse.ts` — `parse`.
|
||||
- [x] 3.3 `src/core/validator/validate.ts` — `validate`.
|
||||
|
||||
## 4. Parsers
|
||||
- [x] 4.1 `src/parsers/apple-passwords/*`.
|
||||
- [x] 4.2 `src/parsers/bitwarden/*` (handle encrypted detection).
|
||||
- [x] 4.3 `src/parsers/chrome/*`.
|
||||
- [x] 4.4 `src/parsers/keepass/*` (unencrypted `kdbx` XML export only).
|
||||
- [x] 4.5 `src/parsers/lastpass/*`.
|
||||
- [x] 4.6 `src/parsers/onepassword/*` (CSV + `.1pux` zip via `fflate`).
|
||||
- [x] 4.7 Co-located `.md` + unit tests with real fixture files per format.
|
||||
|
||||
## 5. Exporter
|
||||
- [x] 5.1 `src/exporters/csv-exporter.ts` — `exportToCsv`.
|
||||
- [x] 5.2 Round-trip property test.
|
||||
|
||||
## 6. Index / README / exports
|
||||
- [x] 6.1 Barrel, subpath exports per parser.
|
||||
- [x] 6.2 Root README.
|
||||
|
||||
## 7. Benchmarks
|
||||
- [x] 7.1 `parse.bench.ts` for 1 k / 10 k / 100 k entries.
|
||||
|
||||
## 8. Ship gate
|
||||
- [x] 8.1 Verification sequence; fold spec + archive.
|
||||
Reference in New Issue
Block a user