Compare commits

..

2 Commits

Author SHA1 Message Date
matmoul 9496c07049 feat: add publish script to merge dev changes into main 2026-05-10 00:02:04 +02:00
matmoul 4cb568c326 fix: default bridge and tests to project venv Python
Use .venv/bin/python3 by default, with PYTHON_PATH as an override, and update the setup script and docs to match the new virtualenv-based workflow.
2026-05-10 00:00:56 +02:00
6 changed files with 87 additions and 65 deletions
+20 -58
View File
@@ -1,58 +1,20 @@
# kdbx-lib
TypeScript wrapper around `pykeepass` for read-only access to KeePass `.kdbx` files.
## Architecture
- Public API: TypeScript
- Runtime backend: Python 3
- Bridge: `src/python/bridge.py`
- Transport: JSON over stdin/stdout
- Backend library: `pykeepass`
## Requirements
- Node.js or Bun
- Python 3
- `pykeepass` installed in the Python environment used by the bridge
- A project-local `.venv` works well
## Python setup
Install dependencies with:
```bash
bun run setup:python
```
Manual alternative:
```bash
python3 -m pip install pykeepass
```
## Core behavior
- Read-only library; it does not modify databases.
- `openKeePassDatabase(path, options)` opens a database through the Python bridge.
- `listEntries()` returns all entry fields exposed by the bridge: `title`, `username`, `password`, `url`, `notes`, `groupPath`, and `otp` when present.
- `findEntries(query)` performs partial matching and returns full entries.
- `listGroups()` returns group names and paths.
- `close()` is currently a no-op.
## Fixture facts
- Bundled fixtures: `tests/fixtures/data.kdbx` and `tests/fixtures/empty.kdbx`
- Fixture passwords and expected content live in companion JSON files
- `data.kdbx` contains four entries: `root`, `otp1`, `f1-item1`, `f2-item1`
- The fixture tree is `Racine/ -> root, otp1, Folder1/ -> f1-item1, Folder2/ -> f2-item1`
- Integration tests cover entries, groups, and the `otp1` OTP/TOTP value
- Canonical OTP value is the full `otpauth://...` URI returned by `pykeepass`
## Notes
- The bridge currently launches a Python process per call; simple but expensive.
- Errors from the bridge are propagated to TypeScript, including exit code when available.
- The API is still flatter than the real KeePass model.
- More failure-path tests are needed.
- Future improvement: a persistent Python process if performance becomes important.
{
"name": "kdbx-lib",
"packageManager": "bun@1.0.0",
"version": "0.1.0",
"private": true,
"type": "module",
"scripts": {
"example": "bun run src/example.ts",
"validate": "bun run test",
"test": "bun test",
"test:unit": "bun test",
"test:integration": "bun run src/test-integration.ts",
"setup:python": "python3 -m venv .venv && .venv/bin/pip install pykeepass"
},
"dependencies": {},
"devDependencies": {
"typescript": "^5.5.0",
"bun-types": "^1.1.0"
}
}
+3 -2
View File
@@ -16,6 +16,7 @@ The TypeScript layer launches a Python bridge and exchanges JSON through stdin/s
- Node.js or Bun
- Python 3
- `pykeepass` installed in the Python environment used by the bridge (the project provides `bun run setup:python`)
- The bridge defaults to `.venv/bin/python3` when available, or you can override with `PYTHON_PATH`
## Python setup
@@ -28,10 +29,10 @@ bun run setup:python
If you prefer manual installation:
```bash
python3 -m pip install pykeepass
python3 -m venv .venv && .venv/bin/pip install pykeepass
```
The bridge also works with a project-local virtual environment such as `.venv` if you want to pin Python dependencies.
The bridge also works with a project-local virtual environment such as `.venv` and the tests will use it when present.
## Usage
Executable
+59
View File
@@ -0,0 +1,59 @@
#!/bin/bash
set -e
current_branch=$(git branch --show-current)
if [ -z "$current_branch" ]; then
echo "Erreur : impossible de détecter la branche courante."
exit 1
fi
if [ "$current_branch" = "main" ]; then
echo "Erreur : ce script ne peut pas être exécuté depuis la branche main."
exit 1
fi
start_branch="$current_branch"
cleanup() {
if [ "$(git branch --show-current)" != "$start_branch" ]; then
git checkout "$start_branch" >/dev/null 2>&1 || true
fi
}
merge_or_fail() {
source_branch="$1"
target_branch="$2"
if ! git merge "$source_branch"; then
echo "Erreur : conflit lors du merge de $source_branch vers $target_branch."
echo "Résolvez les conflits manuellement, puis relancez le script."
exit 1
fi
}
trap cleanup EXIT
echo "Branche courante détectée : $current_branch"
read -r -p "Confirmer l'exécution sur cette branche ? [y/N] " confirm
case "$confirm" in
y|Y|yes|YES)
;;
*)
echo "Annulé."
exit 1
;;
esac
if [ "$current_branch" != "dev" ]; then
git checkout dev
merge_or_fail "$current_branch" "dev"
git push
current_branch="dev"
fi
git checkout main
merge_or_fail dev main
git push
git checkout dev
+1 -1
View File
@@ -10,7 +10,7 @@
"test": "bun test",
"test:unit": "bun test",
"test:integration": "bun run src/test-integration.ts",
"setup:python": "python3 -m pip install pykeepass"
"setup:python": "test -x .venv/bin/python3 || python3 -m venv .venv && .venv/bin/pip install pykeepass"
},
"dependencies": {},
"devDependencies": {
+1 -1
View File
@@ -13,7 +13,7 @@ export class KeePassDatabase {
constructor(
private readonly path: string,
private readonly options: KeePassOpenOptions,
private readonly pythonPath = "python3",
private readonly pythonPath = process.env.PYTHON_PATH ?? ".venv/bin/python3",
private readonly bridgePath = new URL("./python/bridge.py", import.meta.url)
) {}
+3 -3
View File
@@ -26,7 +26,8 @@ const FIXTURE_PATH = "tests/fixtures/data.kdbx";
const FIXTURE_DATA_PATH = "tests/fixtures/data.kdbx.json";
async function ensurePyKeePass(): Promise<boolean> {
const child = Bun.spawn(["python3", "-c", "import pykeepass; print('ok')"], {
const python = process.env.PYTHON_PATH ?? ".venv/bin/python3";
const child = Bun.spawn([python, "-c", "import pykeepass; print('ok')"], {
stdout: "pipe",
stderr: "pipe",
});
@@ -95,7 +96,7 @@ test("lists the groups from the bundled data fixture", async () => {
}
const db = openKeePassDatabase(FIXTURE_PATH, { password });
const groups = await db.listGroups();
const groups = await db.listGroups();
expect(groups).toEqual([
{ name: "Racine", path: "" },
{ name: "Folder1", path: "Folder1" },
@@ -145,4 +146,3 @@ test("uses the JSON fixture content as the source of truth for expectations", as
"\t\t- f2-item1",
]);
});