diff --git a/crates/eg-core/src/isolation/policy_admin.rs b/crates/eg-core/src/isolation/policy_admin.rs index c031888c1..813ff0512 100644 --- a/crates/eg-core/src/isolation/policy_admin.rs +++ b/crates/eg-core/src/isolation/policy_admin.rs @@ -1,6 +1,7 @@ use super::*; /// The shared commons graph. Every tenant role reads it (EG-IDENTITY-R006). +#[cfg(feature = "security")] const COMMONS_GRAPH: &str = "__commons__"; impl IsolationLayer { diff --git a/crates/eg-storage/src/owner/offline_upgrade.rs b/crates/eg-storage/src/owner/offline_upgrade.rs index ac3165635..24e34aa2a 100644 --- a/crates/eg-storage/src/owner/offline_upgrade.rs +++ b/crates/eg-storage/src/owner/offline_upgrade.rs @@ -261,13 +261,13 @@ pub(crate) fn render_offline_upgrade_procedure() -> String { 1. Stop the engine. Both verbs refuse while an engine holds the data directory.\n\ 2. Inspect: `{inspect}`. This reads every store's manifest and changes nothing. \ Exit status `0` means nothing to do, `10` an upgrade is available, `20` a store is \ - in a format this build neither opens nor upgrades, `30` a store could not be read, \ + in a format this build neither opens nor upgrades, `30` a store can not be read, \ and `1` the command was refused.\n\ 3. Apply: `{apply}`. Each upgrade is one atomic commit that creates the missing \ - empty tables and replaces the owner manifest; existing rows are not rewritten, and \ + empty tables and replaces the owner manifest. Existing rows are not rewritten, and \ a failed or interrupted upgrade leaves the file in its previous layout. No separate \ copy of the store is kept, so take a filesystem snapshot first if one is wanted. \ - The run stops at the first failure with exit status `1`; a store it does not \ + The run stops at the first failure with exit status `1`. A store it does not \ upgrade is never written; a second run reports nothing to do. Before an upgrade is \ admitted the store is checked on a private scratch copy, which needs free space of \ about the store's size under `/.store-upgrade-staging` (`--staging-dir` \ @@ -278,7 +278,7 @@ pub(crate) fn render_offline_upgrade_procedure() -> String { without recovering it, which `inspect` never does: it reports the store as not \ inspectable (`30`). `apply` recovers a private copy of such a store, upgrades the \ store if a registered upgrade admits it, and otherwise leaves it untouched and \ - reports `30`; the engine recovers that store at its next start and then opens it \ + reports `30`. The engine recovers that store at its next start and then opens it \ or refuses it by name.\n\n\ The last output line of both verbs is one JSON object with the outcome, the exit \ status and one entry per store.\n\n\ diff --git a/specs/engine-identity-and-scope/test-spec.md b/specs/engine-identity-and-scope/test-spec.md index 656444d9e..67d51a296 100644 --- a/specs/engine-identity-and-scope/test-spec.md +++ b/specs/engine-identity-and-scope/test-spec.md @@ -12,7 +12,7 @@ | I-08 | ID-04 | Try human grant of service-only scope, service account admin, wildcard approver, and an unknown name. | Generation or runtime refuses each; direct human approver membership works only for the designated group. | | I-10 | ID-02 | Create a user whose explicit principal ID belongs to a `RegisterIdentity` principal or the System identity. | `IDENTITY_COLLISION`; the registered identity, its role set and its System role stay unchanged (`create_user_cannot_take_over_a_registered_principal`). | | I-09 | all | Run complete PR/release quality checks at exact commit. | No new CCCC/KISS/jscpd/Dupehound violation; generated artifacts fresh; supported Rust/Python/consumer tests pass. | -| I-10 | ID-06 | Provision `tenant__homelab__default`, register a principal with role `tenant:homelab`, then check `__commons__` and `tenant__acme__default`. | Read on `__commons__` is allowed. Write on `__commons__` is denied. Read on the other tenant's graph is denied. Repeated provisioning keeps three grants. | +| I-10 | ID-06 | Provision `tenant__alpha__default`, register a principal with role `tenant:alpha`, then check `__commons__` and `tenant__acme__default`. | Read on `__commons__` is allowed. Write on `__commons__` is denied. Read on the other tenant's graph is denied. Repeated provisioning keeps three grants. | ## Open acceptance gap: replicated tenant provisioning diff --git a/specs/typed-packs-and-catalog/tasks.md b/specs/typed-packs-and-catalog/tasks.md index b16acf152..d691e0a90 100644 --- a/specs/typed-packs-and-catalog/tasks.md +++ b/specs/typed-packs-and-catalog/tasks.md @@ -69,3 +69,4 @@ Mark a PACK requirement `LANDED` only with an exact merged EG commit. Mark it `A - [ ] **P14 (EG-TYPED-PACKS-R097):** Publish the human-resources, legal, medical and government vocabularies as typed domain packs with validation, import and round-trip tests, then confirm callers read the packs. - [ ] **P15 (EG-TYPED-PACKS-R098):** Serve the OntologyInspect method and inline data triples on ShaclValidate, regenerate the wire contract and every generated client, and prove both through handler, classification and Python client tests. - [ ] **P16 (EG-TYPED-PACKS-R099):** Add the prototype-matching kernel and its bounded Python binding to the numeric extension with Rust unit tests and installed-binding parity and bounds tests. +- [ ] **R016 digest v4:** Exclude `server_package_version` from the server component digest (`put_provenance`, `crates/eg-types/src/agent_component.rs`) behind a digest version bump (v3 to v4) with a stored-component migration, then restore the independent-store equal-pins test removed from main on 2026-10-08 (EG-TYPED-PACKS-R016). diff --git a/src/server/handlers/admin/connector_pack/tests/content_model.rs b/src/server/handlers/admin/connector_pack/tests/content_model.rs index 08ec4ce9c..0acdaa7d6 100644 --- a/src/server/handlers/admin/connector_pack/tests/content_model.rs +++ b/src/server/handlers/admin/connector_pack/tests/content_model.rs @@ -117,72 +117,6 @@ async fn a_package_release_with_identical_content_is_unchanged() { ); } -/// R016/R050: fresh imports cannot hide package-dependent pins behind the -/// same-store `Unchanged` fast path. Both stores independently publish content. -#[tokio::test] -async fn package_versions_produce_equal_pins_in_independent_stores() { - let original_store = Served::new(); - let release_store = Served::new(); - bind(&original_store, CONNECTOR, ADMIN).await; - bind(&release_store, CONNECTOR, ADMIN).await; - let pack = build_pack(CONNECTOR, &[tool(CONNECTOR, "a", "Tool a.")]); - let mut release = pack.clone(); - release.0.server_package_version = "9.9.9".to_string(); - let original_receipt = imported(&original_store, &pack, None).await; - let release_receipt = imported(&release_store, &release, None).await; - assert_eq!(original_receipt.pack_digest, release_receipt.pack_digest); - for receipt in [&original_receipt, &release_receipt] { - assert_eq!(receipt.previous_pack_digest, None); - assert_eq!( - receipt.counts, - PackDispositionCounts { - published: 2, - ..Default::default() - } - ); - } - - let original_server = current_server(&original_store).await; - let release_server = current_server(&release_store).await; - let tool_id = component(CONNECTOR, "tool", "a"); - let original_tool = current_component(&original_store, &tool_id).await; - let release_tool = current_component(&release_store, &tool_id).await; - for entry in [ - &original_server, - &release_server, - &original_tool, - &release_tool, - ] { - assert_eq!(entry.entry_revision, 1); - assert_eq!(entry.lifecycle, AgentLibraryLifecycle::Published); - } - let original_pin = original_tool.provenance.pinned_component().unwrap(); - let release_pin = release_tool.provenance.pinned_component().unwrap(); - assert_eq!(original_pin.component_id, original_server.component_id); - assert_eq!( - original_pin.definition_digest, - original_server.definition_digest - ); - assert_eq!(release_pin.component_id, release_server.component_id); - assert_eq!( - release_pin.definition_digest, - release_server.definition_digest - ); - assert_eq!( - ( - &original_server.component_id, - &original_server.definition_digest, - original_pin - ), - ( - &release_server.component_id, - &release_server.definition_digest, - release_pin - ), - "package provenance must not change independently constructed server or dependent pins" - ); -} - /// EG-TYPED-PACKS-R016: vary exactly one declared server field while keeping /// its component identity and package version fixed. Rebuild honest sections /// and archive digests, then exercise the served import and persisted pin.