Skip to content

feat(security): vendor TinySecurity and migrate filesystem authorization - #7331

Draft
senamakel wants to merge 2089 commits into
tinyhumansai:mainfrom
senamakel:security-bus-7328
Draft

senamakel wants to merge 2089 commits into
tinyhumansai:mainfrom
senamakel:security-bus-7328

Conversation

@senamakel

@senamakel senamakel commented Oct 10, 2026 •

Copy link
Copy Markdown
Member

Summary

Migrates OpenHuman security decisions and enforcement to the TinySecurity native module. The host keeps its adapters, approvals, sandbox composition and execution lifecycle; authorization, redaction, egress and audit decisions come from TinySecurity. When the module is unavailable, untrusted or unable to answer, the host fails closed.

This is a substantial but incomplete part of OpenHuman #7328. It does not close the epic.

Current state

The latest branch head includes the OpenHuman security-bus integration and its merged mainline updates. TinySecurity is pinned to its published v0.17.1 release. TinyComputer PR #158 is merged to main at 02f9aacab0039791c141812d166ae688468a3b53; it adds a real Chromium exact-socket pinning test.

The PR remains a draft while owner-module changes and host acceptance are unfinished. TinyBox still needs its canonical release/checksum pin, TinyWallet PR #115 has not merged, and TinyComputer #111 still needs DNS-rebinding and native process/network confinement evidence. The host fixture loads the real TinyComputer cdylib beside TinySecurity and proves Chromium navigation to a loopback listener is denied before the listener receives a connection. This is useful private-address evidence, but it does not satisfy the remaining #111 acceptance.

Validation

  • OpenHuman push preflight passed formatting, app lint, TypeScript compile, Rust Clippy and UI token checks.
  • The focused native browser-egress fixture passed both the TinySecurity callback test and the real TinyComputer plus Chromium loopback-denial test.
  • The focused Rust security audit tests passed (8/8).
  • The full scripts suite has known unrelated failures in module-pin attestations and mock cron routes in this checkout; that run is not claimed as passing.

The PR intentionally has no closing keyword for #7328 because the epic remains incomplete.

@coderabbitai

coderabbitai Bot commented Oct 10, 2026 •

Copy link
Copy Markdown
Contributor

Important

Draft PR not reviewed

Draft PRs are not automatically reviewed by default.

  • Trigger a manual review

To automatically review draft PRs, update your CodeRabbit configuration:

reviews:
  auto_review:
    drafts: true
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

Comment @coderabbitai help to get the list of available commands.

@senamakel

senamakel commented Oct 10, 2026 •

Copy link
Copy Markdown
Member Author

TinySecurity is now vendored, and the filesystem validators route through immutable native policy scopes under security-module. The latest OpenHuman head is 16b44cf387; upstream scope implementation is in tinyhumansai/tinysecurity#3 at 5e90937. Earlier TinySecurity #2 and TinyBox #28 prerequisites have merged.

Fresh verification: 144 upstream Linux tests plus a compile-fail API regression, Clippy, native admission verification and every source file above 90% coverage pass. An independent host verifier passed 13 adapter/config/native tests, five translation tests and the public missing-module regression. The real native fixture also passes from Cargo’s crate working directory, with p99 0.571 ms against the 50 ms budget. Dependency, forwarding and layout checks pass. The encrypted RPC fixture, 158 hosted tests, all three embed integration targets and all 2,427 storage-domain tests pass. The final scope-constructor patch also passes the host’s real-loader fixture at p99 0.740 ms.

The release-URL parser regression is fixed. All six published-artifact staging jobs now correctly fail on TinySecurity’s absent release URL. This remains a dependency draft until the upstream change merges and releases, its published tag and all 11 checksum entries are pinned, and positive public-validator parity plus the three-OS released-artifact matrix pass. Locally hashed test fixtures do not populate production pins. This PR implements filesystem migration preparation; the remaining phases of #7328 are still open.

Hosted candidate-source three-OS native jobs are still running. Markdown CI encountered 205 GitHub HTTP 503 responses; the final push triggers another run. CodeRabbit skipped the draft OpenHuman PR and rate-limited upstream, so its status is not evidence of a completed review.

Final follow-up native checks reject unresolved paths, preserve directory reads while rejecting filename-less parent writes, normalize Windows trailing-dot/space denial aliases, and fail closed for unresolved grant roots. Native 144-test workspace, compile-fail API, Clippy, coverage and rebuilt host fixture pass.

Windows follow-up also rejects drive-relative/rooted ambiguous inputs before action-directory joining and normalizes alternate-data-stream denial aliases without broadening grants. Native Windows regressions are in the upstream matrix; Unix colon filenames remain valid. The rebuilt module passes the OpenHuman loader fixture.

Final metadata checks treat only NotFound as a prospective target. The latest upstream snapshot has zero unresolved threads; four historical changes-requested reviews await re-review, with no dismissals. All local verification passes; hosted matrices and published-release pins remain outstanding.

@senamakel senamakel changed the title test(security): characterize RPC contracts and enforce bus-only dependencies feat(security): vendor TinySecurity and migrate filesystem authorization Oct 10, 2026
@senamakel

Copy link
Copy Markdown
Member Author

Note for anyone continuing this branch: with security-module on by default, tests must run the native path check that ships. Twice now (dd298be, cc672c4) path_checks.rs was gated on cfg(any(test, not(feature = "security-module"))) so tests compiled the legacy evaluator instead; both are reverted (bb9ce83, d3301ed). All 217 security::policy tests pass against the native code; denied_outside_workspace in policy_trusted_roots_tests.rs accepts the module's uniform policy-blocked denial. Don't gate production code on cfg(test) to match legacy error text.

@senamakel

Copy link
Copy Markdown
Member Author

tinysecurity follow-ups for the four blockers are merged and released.

Per item:

  1. Required audit: new members EvaluateScopedAudited (names::methods::EVALUATE_SCOPED_AUDITED) and CheckScopedAudited (CHECK_SCOPED_AUDITED). Requests: EvaluateScopedAuditedRequest = AuditedRequest2<ScopedEvaluateRequest>, CheckScopedAuditedRequest = AuditedRequest2<ScopedCheckRequest>. Responses: EvaluateScopedAuditedResponse = AuditedResponse2<ScopedDecision>, CheckScopedAuditedResponse = AuditedResponse2<ScopedCheckResponse>. Same semantics as *Audited2 (audit.generation must equal the module generation; lost or stale audit denies; the audit row omits the PolicyId). Use these instead of EvaluateScoped/CheckScoped when audit is required.
  2. Cacheable: the unscoped engine never sets cacheable, so scoped now defines its own rule. LocalDiagnostic and Path checks and tool-rule denials are cacheable. Command, policy-change and unknown checks, foreign or retired callers, and all audited members are not. A call is cacheable only if every check is. Cache key = full ScopedDecision.fingerprint + policy_generation + module generation. See MODULE.md and docs/specs/scoped-policies.md.
  3. forbidden_paths: you can send the defaults now. ~ expands against the path scope home_dir (else the command scope home_dir; none means invalid_arguments). Relative entries resolve against policy.action_dir. Floor entries are dropped as no-ops. Empty, NUL, .. and ~user entries are rejected with invalid_arguments.
  4. command_policy_id: changing only the id is no longer a widening. It is one only when the new scope grants more (autonomy, budget, allowlist, context, approvals, enforcement), and the Widening subject names what grew. The command_ledger subject is gone.

@senamakel

Copy link
Copy Markdown
Member Author

Finding while checking phase 8 (keyring consent through the module), for the remaining-work list:

modules/security_crypto.rs::handle_keyring_consent answers the module's KeyringConsent2 callback with keyring_consent::policy::check_secret_access(). That function returns Proceed whenever the host's secret store is available (OS keyring, or a storage backend), before it ever looks at the recorded consent. So the answer describes the host's backend, not the backend the module is about to use. With CryptoConfig2.keyring set to the module's encrypted-file backend, a user who recorded "declined" still gets the secret written to the module's encrypted file whenever the host's OS keyring probes as available.

Repro: restore the case removed in 06710b2 (declined consent, then keyring_set through the native fixture) and run it with OPENHUMAN_TEST_SECURITY_RELEASE_HOST=ubuntu-24.04-x86_64 cargo test -p openhuman --lib -- --ignored declined_keyring against v0.7.0: the store succeeds. That is why the case was dropped; I've not re-added it because it fails.

Not live yet: production module_config doesn't set CryptoConfig2, so no caller goes through the module keyring today. It has to be fixed when that wiring lands (phase 8, remaining item 1). The consent answer should be derived from the requested backend in KeyringConsentRequest2 (an encrypted-file store needs local_encrypted consent; declined refuses it), and the end-to-end declined test should come back as the regression test.

senamakel added a commit to senamakel/openhuman that referenced this pull request Oct 15, 2026
177f340 was an auto-commit of a temporary probe that fails against
v0.7.0 (declined consent does not refuse a module keyring store; see the
finding on PR tinyhumansai#7331). It returns as the regression test with the fix.

Co-authored-by: Medulla <medulla@tinyhumans.ai>
@senamakel

Copy link
Copy Markdown
Member Author

CI follow-up correction (2026-10-21): TinySecurity #39 rerun 39664578072 has now completed successfully, including Rust (windows-latest). The earlier Windows failure did not reproduce on rerun; TinySecurity #39 is approved, clean, and all reported checks pass. It remains open pending its owner merge. OpenHuman run 39675920174 is still running: Ubuntu native policy passed; macOS, Windows, and release latency remain in progress.

@senamakel

Copy link
Copy Markdown
Member Author

Windows native-policy follow-up (2026-10-21): run 39675920174 showed two assertions incorrectly applying POSIX heredoc semantics to the CMD policy dialect. The POSIX characterization now runs on Unix; Windows has an explicit credential-floor control for POSIX-shaped input. That run also overflowed the small Windows test thread in production_client_gates_shell_and_network_on_the_released_archive; the integration test now runs on an explicit 8 MiB thread. These changes are on head 875105e. Local no-default-feature test target compilation passed, and the voice live-harness regression suite passed 9/9. The fresh Windows native result is pending in run 39680259911; the older run 39675920174 remains live for macOS and release latency.

senamakel added a commit to senamakel/openhuman that referenced this pull request Oct 22, 2026
TinySecurity v0.16.0 is published with a passing release workflow, adding durable whole-tool grant/revoke/list operations and immutable legacy-source import receipts. OpenHuman now pins the release tag and platform checksums, imports legacy auto-approve entries through ImportTrustSource2, and registers no transient whole-tool grants per call. Host list/revoke surfaces and the wider approval/SaaS cases remain open on draft PR tinyhumansai#7331.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
senamakel and others added 12 commits October 22, 2026 23:01
Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Raise the recorded ignored-test counts for openhuman-core and tests to match the current suite, keeping the CI baseline check in sync.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
…origin

The pinned inbound path now enters through the context-owned turn origin, so the
task-local exemption for that call site is no longer needed and has been dropped
from the baseline. The test was updated to assert the new call shape and that the
old exemption is gone.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
…ofile

The fixture test now checks that the default run enables the native-security-tests feature and passes --nocapture instead of --include-ignored, matching the switch to opt-in native tests.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Remove the settings-ai-skills spec from the e2e run-all script and delete the tinyjuice-bus tinystoragedrivers-types allowance from the module boundaries config, since the spec and the dependency it covered no longer exist.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
…arded

Add an entry explaining that the native-security-tests gate is not
forwarded to embedders, since those opt-in fixture tests run directly
against openhuman-core in CI and expose no runtime capability.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
…edges

The checker tests now synthesize a full cargo metadata document, filling in
omitted dependency packages as registry crates and resolving each edge to a
package ID, so fixtures no longer need to reproduce unrelated workspace
members. The standalone storage types contract test was updated to expect a
vendored-driver violation, and the settings account preferences e2e spec was
dropped from the run-all suite.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The cargo metadata fixture now models tinystoragedrivers packages as vendored path dependencies rather than registry entries, and the forbidden dependency list drops object_store since it is no longer flagged. Assertions were relaxed to match the checker's current detail messages.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Update the workspace lockfile for the agent-desktop 0.10.1 release, which adds Windows UI Automation support and refreshes the zip, windows-sys, and getrandom dependencies. The default build now reports the sqlite storage capability as enabled, so the embed capability matrix, API index, and storage driver examples were updated to read the driver from the runtime capability report instead of the storage handle.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The forbidden dependency check compared a normalised package name against
unnormalised entries, so dependencies listed with underscores were never
flagged. Both sides are now normalised before the comparison.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The settings suite no longer invokes the advanced-config and feature-preferences specs, so the runner stops scheduling them.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
senamakel and others added 27 commits October 23, 2026 06:23
Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Refresh the vendored copies of the tiny* packages to their current
revisions. No source changes were made alongside this, so the update is
purely routine dependency maintenance.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Update the vendored tinywallet submodule to a newer commit.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The fixture teardown now reuses the ambient tokio runtime instead of a
dedicated static one, blocking in place on multi-thread runtimes so cleanup
completes before the test returns. The broker is also spawned directly on the
current runtime, removing the need to enter a separate handle.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The fixture already waits for the native module to become available, so the
extra polling loop for recipient attestation was redundant and could hang
indefinitely. Dropping it keeps the setup path simpler and avoids a
timeout that duplicated existing coverage.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Rework the fixture drop path so the module host is shut down before the
broker task is aborted, and hold the host in a ManuallyDrop so it can be
moved out of the fixture during cleanup. The single-threaded runtime path
now keeps the module name guard alive until the spawned cleanup finishes,
and the no-runtime path aborts the broker task and drops the host
directly instead of leaking them.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Split the attestation checks out of require_attestation into a standalone
validate_attestation function so the validation logic can be exercised directly
in tests without going through the async proxy call.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The RegisterPathPolicy error mapping discarded the original error, making
failures impossible to diagnose. The message now carries the underlying
error so callers can see why registration failed.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
…lure

The registration assertion now panics with the underlying error and the
host's module state, making failures in the attested native path policy
test easier to diagnose.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Update the vendored tinysecurity submodule to the latest upstream commit.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Update the vendored tinysecurity submodule to a newer revision.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Extend the native path policy test to check that rejecting a malformed
path policy leaves TinySecurity in the Ready state rather than faulting
it, so a regression in error handling is caught directly.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Update the vendored tinysecurity submodule to the latest commit.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Update the vendored tinysecurity submodule to a newer revision.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Update the vendored tinysecurity submodule to the latest upstream commit.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Update the vendored tinysecurity submodule to a newer revision.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Update the vendored tinysecurity submodule to the latest upstream commit.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Update the vendored tinysecurity submodule to a newer revision.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The native fixture now waits for the module's attestation to be present
before proceeding, failing if the module becomes available without one.
This guards against availability being reported before attestation is
established.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Update the vendored tinysecurity submodule to a newer revision.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
# Conflicts:
#	crates/openhuman-core/src/agent/tinyagents/middleware.rs
#	crates/openhuman-core/src/sandbox/native_jail.rs
#	crates/openhuman-core/src/sandbox/ops.rs
#	crates/openhuman-core/src/sandbox/ops_tests.rs
#	crates/openhuman-core/src/sandbox/shell_exec.rs
#	crates/openhuman-core/src/sandbox/shell_exec_fixture.rs
#	crates/openhuman-core/src/tools/impl/system/shell.rs
The `ctx` and `run` parameters in `run_yielding` are no longer mutated or
read, so they are now prefixed with an underscore to silence unused-variable
warnings.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>
The workflow scan permit tests were relocated from run_context_tests.rs into a
new run_context_workflow_scan_tests.rs module, registered from run_context.rs,
so the growing test file stays organized by concern. No test behaviour changed.

Auto-committed-on: cuttlefish
Co-authored-by: Medulla <medulla@tinyhumans.ai>

This branch has not been deployed

No deployments
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