Initial DataLoom project scaffold
This commit is contained in:
+20
@@ -0,0 +1,20 @@
|
|||||||
|
__pycache__/
|
||||||
|
*.py[cod]
|
||||||
|
*.egg-info/
|
||||||
|
.venv/
|
||||||
|
.pytest_cache/
|
||||||
|
.mypy_cache/
|
||||||
|
.ruff_cache/
|
||||||
|
dist/
|
||||||
|
build/
|
||||||
|
|
||||||
|
# Sensitive vault exports, logs, and local runtime state
|
||||||
|
*.json
|
||||||
|
*.csv
|
||||||
|
*.log
|
||||||
|
*.txt
|
||||||
|
!README.md
|
||||||
|
!docs/*.md
|
||||||
|
!tests/fixtures/*.json
|
||||||
|
!tests/fixtures/*.csv
|
||||||
|
!tests/fixtures/*.txt
|
||||||
@@ -0,0 +1,29 @@
|
|||||||
|
# DataLoom
|
||||||
|
|
||||||
|
Offline desktop application for reviewing and merging Bitwarden exports.
|
||||||
|
|
||||||
|
## Status
|
||||||
|
|
||||||
|
Initial project scaffold and design documentation. Implementation has not started.
|
||||||
|
|
||||||
|
## Goals
|
||||||
|
|
||||||
|
- Import two or more same-format, unencrypted Bitwarden exports.
|
||||||
|
- Support JSON and CSV input, preserving all representable Bitwarden data.
|
||||||
|
- Automatically remove only exact duplicates.
|
||||||
|
- Keep uncertain and conflicting records for review.
|
||||||
|
- Produce one merged output in the same format as the inputs.
|
||||||
|
- Provide a comprehensive on-screen and plain-text audit log.
|
||||||
|
- Operate offline with no uploads or external service dependencies.
|
||||||
|
|
||||||
|
## Security note
|
||||||
|
|
||||||
|
Bitwarden exports and the requested full audit log contain secrets. DataLoom must display a prominent warning before import and clearly identify all generated files and their locations. Real exports must never be committed to source control.
|
||||||
|
|
||||||
|
## Planned technology
|
||||||
|
|
||||||
|
Python and PySide6/Qt for a desktop application. The initial implementation will use synthetic fixtures only.
|
||||||
|
|
||||||
|
## Development
|
||||||
|
|
||||||
|
The detailed design is in [`docs/design.md`](docs/design.md). See [`docs/roadmap.md`](docs/roadmap.md) for the planned milestones.
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
# DataLoom design
|
||||||
|
|
||||||
|
## Application
|
||||||
|
|
||||||
|
DataLoom is an offline PySide6/Qt desktop application. It does not upload files, call cloud services, or require a network connection during normal operation.
|
||||||
|
|
||||||
|
## Import rules
|
||||||
|
|
||||||
|
- Accept two or more files in one batch.
|
||||||
|
- Every file in a batch must be Bitwarden JSON or every file must be Bitwarden CSV.
|
||||||
|
- Reject mixed-format batches and encrypted/protected exports.
|
||||||
|
- Validate the expected Bitwarden structure before processing.
|
||||||
|
- Preserve supported item types and unknown JSON fields where possible.
|
||||||
|
- Keep source filename, input index, record index, and Bitwarden item ID as internal provenance metadata for review and logging; do not add it to exported vault records.
|
||||||
|
|
||||||
|
## Duplicate policy
|
||||||
|
|
||||||
|
Only exact duplicates are removed automatically. All uncertain or conflicting records remain in the merged collection and are shown in Duplicate Review.
|
||||||
|
|
||||||
|
### Exact duplicate
|
||||||
|
|
||||||
|
Two records are exact duplicates when they have the same item type and equivalent normalized content, including the relevant login username, password, URI data, folder, notes, custom fields, and other representable fields. Comparisons are case-insensitive where appropriate.
|
||||||
|
|
||||||
|
### Likely duplicate
|
||||||
|
|
||||||
|
Same item type, normalized URL identity, and username, but one or more values differ. These records remain separate.
|
||||||
|
|
||||||
|
### Possible duplicate
|
||||||
|
|
||||||
|
Same item type and normalized URL identity, but different usernames or other identity fields. These records remain separate.
|
||||||
|
|
||||||
|
Non-login records use type-appropriate stable fields and full normalized content. Folder membership is retained but does not alone determine duplication.
|
||||||
|
|
||||||
|
## URL normalization
|
||||||
|
|
||||||
|
Normalize URLs conservatively and case-insensitively by parsing the URL, lowercasing the scheme/host, removing default ports, removing trailing slashes, and applying the configured `www.` equivalence. Query strings and paths remain significant unless Bitwarden-specific behavior establishes otherwise. The original URI is always preserved for export.
|
||||||
|
|
||||||
|
When normalization is ambiguous, retain both records and flag them for review.
|
||||||
|
|
||||||
|
## Newest record preference
|
||||||
|
|
||||||
|
When duplicate records conflict, use Bitwarden `revisionDate` when available and valid. The newest record is preferred only where the timestamp is reliable. CSV commonly lacks sufficient revision metadata; in that case DataLoom keeps a deterministic first record in the merged output, retains all conflicting records in Duplicate Review, and logs that newest selection was unavailable.
|
||||||
|
|
||||||
|
## Review interface
|
||||||
|
|
||||||
|
1. **Import Summary** — files, format, counts, validation warnings, and output locations.
|
||||||
|
2. **Merged Entries** — records included in the output, with provenance and classification.
|
||||||
|
3. **Duplicate Review** — grouped likely/possible duplicates and exact-duplicate removal decisions, with side-by-side differences.
|
||||||
|
4. **Audit Log** — live in-app view and persistent plain-text log.
|
||||||
|
|
||||||
|
The workflow is automated; there is no general record editor. Review is read-only in the first version.
|
||||||
|
|
||||||
|
## Audit logging
|
||||||
|
|
||||||
|
The requested log records every file and record viewed, fields inspected, comparisons, classifications, selection decisions, warnings, and exports, including secret values. Because this log is equivalent in sensitivity to a vault, the import warning must explicitly state that it contains secrets. The user is responsible for retaining and deleting the log. DataLoom must never log secrets from its own synthetic fixtures into repository files.
|
||||||
|
|
||||||
|
## Export
|
||||||
|
|
||||||
|
- JSON input produces JSON output.
|
||||||
|
- CSV input produces CSV output.
|
||||||
|
- JSON is the lossless preferred format.
|
||||||
|
- Before CSV export, report any fields that CSV cannot represent completely (for example, nested/custom structures, passkey data, or attachment metadata).
|
||||||
|
- Never silently discard unsupported data.
|
||||||
|
|
||||||
|
## Data lifecycle
|
||||||
|
|
||||||
|
DataLoom does not automatically delete input, output, or log files. After processing it displays the exact locations of all generated files. Real exports and generated vault/log files are ignored by Git.
|
||||||
@@ -0,0 +1,12 @@
|
|||||||
|
# Roadmap
|
||||||
|
|
||||||
|
1. Define internal record model and synthetic JSON/CSV fixtures.
|
||||||
|
2. Implement strict same-format Bitwarden import and validation.
|
||||||
|
3. Implement loss-aware field preservation and URL normalization.
|
||||||
|
4. Implement exact/likely/possible duplicate classification and newest-record preference.
|
||||||
|
5. Implement same-format merged export with CSV loss warnings.
|
||||||
|
6. Build PySide6 desktop workflow and read-only review screens.
|
||||||
|
7. Add comprehensive plain-text and in-app audit logging.
|
||||||
|
8. Add packaging documentation and desktop smoke tests.
|
||||||
|
|
||||||
|
Real Bitwarden exports are not required for development or tests.
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
[build-system]
|
||||||
|
requires = ["setuptools>=68"]
|
||||||
|
build-backend = "setuptools.build_meta"
|
||||||
|
|
||||||
|
[project]
|
||||||
|
name = "dataloom"
|
||||||
|
version = "0.1.0"
|
||||||
|
description = "Offline Bitwarden export review and merge desktop application"
|
||||||
|
readme = "README.md"
|
||||||
|
requires-python = ">=3.11"
|
||||||
|
dependencies = ["PySide6>=6.6"]
|
||||||
|
|
||||||
|
[project.scripts]
|
||||||
|
dataloom = "dataloom.app:main"
|
||||||
|
|
||||||
|
[tool.setuptools.packages.find]
|
||||||
|
where = ["src"]
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
"""DataLoom offline Bitwarden export review application."""
|
||||||
|
|
||||||
|
__version__ = "0.1.0"
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
"""Application entry point placeholder for the DataLoom desktop UI."""
|
||||||
|
|
||||||
|
|
||||||
|
def main() -> int:
|
||||||
|
"""Start the desktop application once the UI is implemented."""
|
||||||
|
raise NotImplementedError("DataLoom UI is not implemented yet")
|
||||||
Vendored
+3
@@ -0,0 +1,3 @@
|
|||||||
|
# Synthetic fixtures
|
||||||
|
|
||||||
|
Fixtures in this directory must contain fake credentials only. Never place a real Bitwarden export here.
|
||||||
Vendored
+24
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"encrypted": false,
|
||||||
|
"folders": [],
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "synthetic-a-1",
|
||||||
|
"organizationId": null,
|
||||||
|
"folderId": null,
|
||||||
|
"type": 1,
|
||||||
|
"reprompt": 0,
|
||||||
|
"name": "Example Account",
|
||||||
|
"notes": "synthetic fixture only",
|
||||||
|
"favorite": false,
|
||||||
|
"login": {
|
||||||
|
"username": "fake-user",
|
||||||
|
"password": "not-a-real-password",
|
||||||
|
"uris": [{"match": null, "uri": "https://example.com"}],
|
||||||
|
"totp": null
|
||||||
|
},
|
||||||
|
"revisionDate": "2026-01-01T00:00:00.000Z",
|
||||||
|
"fields": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Vendored
+24
@@ -0,0 +1,24 @@
|
|||||||
|
{
|
||||||
|
"encrypted": false,
|
||||||
|
"folders": [],
|
||||||
|
"items": [
|
||||||
|
{
|
||||||
|
"id": "synthetic-b-1",
|
||||||
|
"organizationId": null,
|
||||||
|
"folderId": null,
|
||||||
|
"type": 1,
|
||||||
|
"reprompt": 0,
|
||||||
|
"name": "Example Account Copy",
|
||||||
|
"notes": "synthetic fixture only",
|
||||||
|
"favorite": false,
|
||||||
|
"login": {
|
||||||
|
"username": "fake-user",
|
||||||
|
"password": "not-a-real-password",
|
||||||
|
"uris": [{"match": null, "uri": "https://www.example.com/"}],
|
||||||
|
"totp": null
|
||||||
|
},
|
||||||
|
"revisionDate": "2026-02-01T00:00:00.000Z",
|
||||||
|
"fields": []
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user