Skip to content

Release 0.4.0a2#39

Open
github-actions[bot] wants to merge 19 commits into
masterfrom
release-0.4.0a2
Open

Release 0.4.0a2#39
github-actions[bot] wants to merge 19 commits into
masterfrom
release-0.4.0a2

Conversation

@github-actions

@github-actions github-actions Bot commented Jun 5, 2026

Copy link
Copy Markdown

Human review requested!

JarbasAl and others added 19 commits April 15, 2026 03:28
* ci: replace hand-rolled release jobs with shared template inputs

The old publish_stable.yml and release_workflow.yml extracted the version
by importing hivemind_sqlite_database, which triggered __init__.py and
pulled in ovos_utils — not present in the bare workflow environment.

Replace all duplicated publish_pypi, sync_dev, propose_release, and notify
jobs with the equivalent inputs on the shared publish-stable.yml@dev and
publish-alpha.yml@dev reusable workflows, which use get_version.py to read
version.py directly without any package import.

AI-Generated Change:
- Model: claude-sonnet-4-6
- Intent: fix version extraction failure in CI release workflows
- Impact: replaced publish_stable.yml, release_workflow.yml
- Verified via: reviewed diff against shared template inputs

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* feat: add optional SQLCipher encryption to SQLiteDB via password kwarg

AI-Generated Change:
- Model: Claude Sonnet 4.6
- Intent: allow operators to encrypt the client database at rest using SQLCipher AES-256
- Impact: SQLiteDB gains a password field; when set, sqlcipher3 is used as the sqlite3
  backend and PRAGMA key is issued immediately after connect; when None (default) the
  existing stdlib sqlite3 path is unchanged; ImportError with install hint raised if
  sqlcipher3 is missing but a password is supplied
- Verified via: python -m pytest tests/test_sqlitedb.py -q -p no:ovoscope (31 passed)

* chore: add cipher optional-dependency extra for sqlcipher3

AI-Generated Change:
- Model: Claude Sonnet 4.6
- Intent: let users opt into SQLCipher encryption via pip install hivemind-sqlite-database[cipher]
- Impact: pyproject.toml gains [project.optional-dependencies] cipher = ["sqlcipher3"]
- Verified via: python -m pytest tests/test_sqlitedb.py -q -p no:ovoscope (31 passed)

* test: add SQLCipher encrypted-path tests (skipped without sqlcipher3)

AI-Generated Change:
- Model: Claude Sonnet 4.6
- Intent: verify encrypted path works end-to-end and existing CI remains green without sqlcipher3
- Impact: TestSQLiteDBEncrypted (3 tests, skipped when sqlcipher3 absent) and
  TestSQLiteDBMissingCipher (ImportError when sqlcipher3 not installed) added
- Verified via: python -m pytest tests/test_sqlitedb.py -q -p no:ovoscope
  (35 passed with sqlcipher3; 32 passed + 3 skipped without)

* docs: document SQLCipher encryption in README and add CI workflow

AI-Generated Change:
- Model: Claude Sonnet 4.6
- Intent: document the password kwarg, install steps, and data-loss warning; add CI
  that tests both plain and encrypted paths
- Impact: README.md rewritten with usage examples, apt/pip install instructions, and
  data-loss warning; .github/workflows/tests.yml added with two jobs (plain sqlite3
  and sqlcipher3)
- Verified via: python -m pytest tests/test_sqlitedb.py -q -p no:ovoscope (35 passed)

* fix(ci): remove libsqlcipher0 from apt install — not present on Ubuntu 24.04

Ubuntu Noble (24.04) replaced libsqlcipher0 with libsqlcipher1.
Installing libsqlcipher-dev is sufficient as it declares a dependency on
libsqlcipher1 and pulls it in automatically.

AI-Generated Change:
- Model: claude-sonnet-4-6
- Intent: fix SQLite + SQLCipher CI job failing with exit code 100
- Impact: `apt-get install -y libsqlcipher0` → removed; libsqlcipher-dev alone satisfies the requirement
- Verified via: gh run log inspection showing "Unable to locate package libsqlcipher0"

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix: address CodeRabbit Major issues in encryption implementation

AI-Generated Change:
- Model: claude-sonnet-4-6
- Intent: address CodeRabbit Major review comments on PR #24

Changes:
- __init__.py: gate on `password is not None` instead of truthiness so
  empty-string passwords don't silently downgrade to plaintext; raise
  ValueError for empty strings
- __init__.py: escape single-quotes in passphrase before building PRAGMA
  key string (SQLite double-quote escaping) to avoid broken opens and
  eliminate an injection surface
- tests/test_sqlitedb.py: rewrite _make_encrypted_db() to drive through
  __post_init__() (patching xdg_data_home) instead of reimplementing the
  SQLCipher setup, so regressions in the production path are caught
- tests/test_sqlitedb.py: remove unused `importlib` import (Ruff F401 /
  CI lint failure)

Verified via: python -m pytest tests/test_sqlitedb.py -q (35 passed)
              python -m ruff check (all checks passed)

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

* fix(ci): address CodeRabbit workflow issues

AI-Generated Change:
- Model: claude-sonnet-4-6
- Intent: address CodeRabbit Critical/Major review comments on CI workflows

Changes:
- tests.yml: add `sudo apt-get update` before apt install to prevent
  intermittent "Unable to locate package" failures on stale runner indexes
- tests.yml: remove broken `|| pip install -e . && pip install sqlcipher3`
  fallback that masked a misconfigured cipher extra; now fails loudly if
  `.[cipher]` is broken (cipher extra is defined in pyproject.toml so
  this is the correct install path)
- release_workflow.yml: add `if: github.event.pull_request.merged == true`
  guard to publish_alpha job so closing a PR without merging does not
  trigger PyPI publish, release proposal, or Matrix notification

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>

---------

Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
* Preserve client metadata

* refactor: require hivemind-plugin-manager>=0.5.0 and drop feature detection

hivemind-plugin-manager 0.5.0 ships Client.metadata, so the
CLIENT_SUPPORTS_METADATA runtime detection and dual code paths are
dead code. Bump the dependency floor and always read/write metadata.

The schema migration (ALTER TABLE ... ADD COLUMN metadata) is kept
for backwards compatibility with DB files created by older versions.

Tests: drop feature-detection skips, add nested-dict and non-ASCII
metadata round-trip coverage.

* test: add metadata helper and update-semantics coverage

- empty-dict default when no metadata kwarg
- INSERT OR REPLACE overwrites metadata on same client_id
- _metadata_to_json returns '{}' for non-dict inputs
- _metadata_from_row coerces NULL / malformed JSON / non-object JSON to {}

* docs: clarify _metadata_to_json/_metadata_from_row contracts

- _metadata_to_json: document that default=str makes datetime/UUID
  insertable but they come back as strings (column is opaque JSON, not
  a typed map)
- _metadata_from_row: document the swallow-garbage rationale (one bad
  row mustn't break iteration)

No behavior change.

---------

Co-authored-by: Gaëtan Trellu <gaetan.trellu@gmail.com>
* ci: pass PYPI_TOKEN explicitly, drop secrets:inherit elsewhere

secrets:inherit fails for the publish workflows (publish-stable,
publish-alpha) — pass PYPI_TOKEN explicitly. For workflows that don't
declare any secrets upstream, drop the secrets: line entirely.

* ci: add workflow_dispatch to release_workflow so alphas can be triggered manually

Other repos in the family (hivemind-plugin-manager, hivemind-ovos-agent-plugin,
HiveMind-core, hivemind-redis-database) all have workflow_dispatch on this
workflow. sqlite was missing it, blocking manual alpha-release triggering.
The previous tests.yml had two jobs:
- test-plain: redundant with the shared build-tests.yml (which already
  runs the unencrypted path across Python 3.10-3.14).
- test-cipher: unique — installs libsqlcipher-dev + the [cipher] extra
  and exercises the SQLCipher path on every PR.

Keep the cipher job, drop the duplicate, rename the file so its
purpose is obvious in the Actions UI. Also align the trigger surface
with the rest of the workflows (pull_request on the named branches +
workflow_dispatch), instead of the catch-all push/PR on every branch.
…tadata (#32)

* feat(db): schema v2 migration — fold legacy blacklist columns into metadata

Overrides AbstractDB.migrate() to merge intent_blacklist /
skill_blacklist / message_blacklist column values into each row's
metadata JSON (setdefault — never clobbers explicit metadata) and NULL
the legacy columns. Migration is gated on PRAGMA user_version,
idempotent, and crash-safe.

Going forward add_item() writes NULL to the legacy columns and
_row_to_client() reads exclusively from metadata, with a defensive
fallback that re-folds legacy data on the fly if a v1-shape row slips
through. Columns themselves stay in the schema for back-compat with
older readers; can be removed in a future major.

Defensive against older HPM (no SCHEMA_VERSION attr): falls back to
v1 / no-op.

* refactor(migrate): purge message_blacklist outright on v1->v2

HPM removed message_blacklist from the Client data model entirely
(the field was a 2024-12-20 design mistake that contradicted the
deny-by-default whitelist model and never functioned as a real gate).
Update the v2 migration to match:

- migrate(): NULL the legacy column without folding into metadata, and
  strip any residual metadata key from earlier migration runs.
- _row_to_client(): pop metadata["message_blacklist"] defensively.

Disk is now clean of message_blacklist after migration runs.

* ci: drop HPM branch pin — exercise partial-upgrade path against released HPM

The plugin guards on getattr(AbstractDB, 'SCHEMA_VERSION', 1) so it
runs cleanly against any HPM version. Running CI against the PyPI HPM
exercises the partial-upgrade scenario operators hit when they upgrade
this plugin before HPM; if CI breaks here, the back-compat contract
has regressed.

* docs: drop history/date references in migrate() docstring

* fix(migrate): bundle schema migration and user_version bump in one tx

Migrate row rewrites and the user_version sentinel write now share a
single sqlite transaction so a crash cannot leave the DB in a
'migrated rows but stale sentinel' (or vice versa) state.

- factor out _migrate_locked() inner body that assumes the caller
  already holds the write lock and is in a transaction
- _maybe_migrate opens one with self._write_lock, self.conn: block,
  calls _migrate_locked, then bumps PRAGMA user_version atomically
- add empty-new-DB migration test asserting sentinel moves to
  SCHEMA_VERSION on a fresh open with zero rows

* feat(db): targeted refresh, forward-compat schema rejection

Override get_client_by_id with a direct primary-key SELECT — used by
AbstractDB.refresh() on the per-message admission hot path.

Call _check_forward_compat in _maybe_migrate so a DB whose user_version
exceeds the backend's SCHEMA_VERSION raises RuntimeError instead of
being silently downgraded.

* ci: drop secrets: inherit, prune main branch, add release workflow_dispatch

* ci: fold dedupe-tests into feat branch — rename tests.yml to cipher-tests.yml

Drop the redundant test-plain job (build-tests.yml already covers the
unencrypted path on Python 3.10-3.14) and rename to cipher-tests.yml so
its purpose is clear. Narrow triggers from catch-all push/PR to
pull_request:[dev,master,main] + workflow_dispatch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* ci(cipher-tests): drop test-plain job, narrow triggers

The shared build-tests.yml already runs the unencrypted path on Python
3.10-3.14. This file becomes cipher-only: drop test-plain, narrow
on.push/PR triggers to [dev, master, main] + workflow_dispatch.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* test(sqlite): add v2 schema round-trip tests

Cover the v2 field set explicitly: allowed_types round-trip,
skill_blacklist/intent_blacklist in metadata survive add→search and
add→refresh, message_blacklist absent from stored records, v1 row
reads cleanly (forward-compat), and refresh returns v2 fields.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>

* chore: restore version.py to dev baseline

* ci: fix pre_install_pip quoting (literal backslashes broke pip)

* ci(cipher): install hivemind-plugin-manager==0.6.0a1 (schema-v2: refresh, migrate, _check_forward_compat)

* test(e2e): migration → policy → session — real SQLiteDB through a hivescope topology asserts a migrated skill_blacklist is injected into the OVOS session (skips until hivescope db= ships)

* test(e2e): importorskip the cross-repo policy stack so the module skips cleanly in the DB plugin's own CI

* ci: dedicated Policy Migration E2E job (pins published policy stack + hivescope db=) to activate the migration→policy→session test

---------

Co-authored-by: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant