From 14e3f0919a33282ff3026c364182f715f5dda634 Mon Sep 17 00:00:00 2001 From: chen21019 <19357113+chen21019@users.noreply.github.com> Date: Fri, 2 Oct 2026 09:27:13 +0800 Subject: [PATCH] fix: protect generic plugin capabilities in low-role API schemas --- .github/workflows/security-release-gate.yml | 14 +- README.md | 26 ++- code/framework/api-pub-sub-jetty/pom.xml | 2 +- code/framework/api-pub-sub/pom.xml | 2 +- code/framework/api/pom.xml | 2 +- code/framework/archaius/pom.xml | 2 +- code/framework/async/pom.xml | 2 +- code/framework/auditing/pom.xml | 2 +- code/framework/db-loader/pom.xml | 2 +- code/framework/deferred/pom.xml | 2 +- code/framework/encryption/pom.xml | 2 +- code/framework/engine/pom.xml | 2 +- code/framework/eventing/pom.xml | 2 +- code/framework/events/pom.xml | 2 +- code/framework/extension-spring/pom.xml | 2 +- code/framework/extension/pom.xml | 2 +- code/framework/java-server/pom.xml | 2 +- code/framework/jmx/pom.xml | 2 +- code/framework/jooq/pom.xml | 2 +- code/framework/json/pom.xml | 2 +- code/framework/launcher/pom.xml | 2 +- code/framework/lock/pom.xml | 2 +- code/framework/logback/pom.xml | 2 +- code/framework/managed-context/pom.xml | 2 +- code/framework/metrics/pom.xml | 2 +- code/framework/module/pom.xml | 2 +- code/framework/object/pom.xml | 2 +- code/framework/pool/pom.xml | 2 +- code/framework/resource-monitor/pom.xml | 2 +- code/framework/schema/pom.xml | 2 +- .../GenericObjectAuthOverlayTest.java | 137 ++++++++++++ code/framework/server/pom.xml | 2 +- code/framework/spring/pom.xml | 2 +- code/framework/system-task/pom.xml | 2 +- code/framework/token/pom.xml | 2 +- code/framework/utils/pom.xml | 2 +- code/iaas/agent-instance/pom.xml | 2 +- code/iaas/agent-server/pom.xml | 2 +- code/iaas/agent/pom.xml | 2 +- code/iaas/allocator/pom.xml | 2 +- code/iaas/api-logic/pom.xml | 2 +- code/iaas/archaius-management/pom.xml | 2 +- code/iaas/auth-logic/pom.xml | 2 +- code/iaas/bootstrap/pom.xml | 2 +- code/iaas/config-item/api/pom.xml | 2 +- code/iaas/config-item/common/pom.xml | 2 +- code/iaas/config-item/server/pom.xml | 2 +- code/iaas/engine-jooq/pom.xml | 2 +- code/iaas/events/pom.xml | 2 +- code/iaas/external-handler/pom.xml | 2 +- code/iaas/ha/pom.xml | 2 +- code/iaas/healthcheck/pom.xml | 2 +- code/iaas/labels/pom.xml | 2 +- code/iaas/logic-common/pom.xml | 2 +- code/iaas/logic/pom.xml | 2 +- code/iaas/metadata/pom.xml | 2 +- code/iaas/model/pom.xml | 2 +- code/iaas/resource-pool/pom.xml | 2 +- code/iaas/service-discovery/api/pom.xml | 2 +- code/iaas/service-discovery/server/pom.xml | 2 +- code/iaas/ssh-common/pom.xml | 2 +- code/iaas/storage-service/pom.xml | 2 +- code/iaas/task-jooq/pom.xml | 2 +- code/implementation/activity-log/pom.xml | 2 +- .../agent-instance-impl/pom.xml | 2 +- code/implementation/docker/api/pom.xml | 2 +- code/implementation/docker/common/pom.xml | 2 +- code/implementation/docker/compute/pom.xml | 2 +- code/implementation/docker/machine/pom.xml | 2 +- code/implementation/docker/storage/pom.xml | 6 +- code/implementation/extension-api/pom.xml | 2 +- code/implementation/hazelcast/common/pom.xml | 2 +- .../implementation/hazelcast/eventing/pom.xml | 2 +- code/implementation/hazelcast/lock/pom.xml | 2 +- code/implementation/host-api/pom.xml | 2 +- code/implementation/host-stats/pom.xml | 2 +- code/implementation/register/pom.xml | 2 +- code/implementation/sample-setup/pom.xml | 2 +- code/implementation/settings-api/pom.xml | 2 +- .../simulator/agent-connection/pom.xml | 2 +- code/implementation/simulator/storage/pom.xml | 2 +- code/implementation/system-stack/pom.xml | 2 +- code/implementation/vm/pom.xml | 2 +- code/meta-parent/pom.xml | 2 +- code/packaging/app-config/pom.xml | 2 +- code/packaging/app/pom.xml | 2 +- code/packaging/bundle/pom.xml | 2 +- code/packaging/dev/pom.xml | 2 +- code/packaging/meta/pom.xml | 2 +- code/parent/pom.xml | 2 +- .../orchestration-engine-0.183.329.md | 51 +++++ pom.xml | 2 +- .../content/schema/read-user/read-user.json | 4 +- .../restricted-user/restricted-user.json | 2 + resources/content/schema/v1/readonly.ser | Bin 340615 -> 340159 bytes resources/content/schema/v1/restricted.ser | Bin 355479 -> 355023 bytes resources/pom.xml | 2 +- .../FrozenGenericObjectRoleSchemaTest.java | 62 ++++++ scripts/build | 2 +- scripts/check-pasturestack-source | 4 +- scripts/check-release-artifact | 14 +- .../UpdateFrozenGenericObjectSchemas.java | 208 ++++++++++++++++++ 102 files changed, 608 insertions(+), 98 deletions(-) create mode 100644 code/framework/schema/src/test/java/io/cattle/platform/schema/processor/GenericObjectAuthOverlayTest.java create mode 100644 docs/releases/orchestration-engine-0.183.329.md create mode 100644 resources/src/test/java/io/cattle/platform/resources/FrozenGenericObjectRoleSchemaTest.java create mode 100644 scripts/java/UpdateFrozenGenericObjectSchemas.java diff --git a/.github/workflows/security-release-gate.yml b/.github/workflows/security-release-gate.yml index 5b79f7d9d6..4c30d634e9 100644 --- a/.github/workflows/security-release-gate.yml +++ b/.github/workflows/security-release-gate.yml @@ -57,6 +57,16 @@ jobs: import xml.etree.ElementTree as ET required = { + 'io.cattle.platform.schema.processor.GenericObjectAuthOverlayTest': { + 'lowRolesHideCapabilitiesAtTheSharedResponseBoundary', + 'inheritedStorageFieldsCannotReintroduceCapabilities', + 'privilegedProjectClientsKeepPluginStorage', + 'pullTaskStorageRemainsPrivateWithoutRemovingTypedStatus', + }, + 'io.cattle.platform.resources.FrozenGenericObjectRoleSchemaTest': { + 'lowRoleFrozenSchemasCannotRevealGenericStorageCapabilities', + 'privilegedProjectSchemasRetainPluginStorage', + }, 'io.github.ibuildthecloud.gdapi.request.handler.BodyParserRequestHandlerTest': { 'mergeMapKeepsRequestParamsAndLetsBodyOverride', 'mergeListRecursivelyMergesAllowedMapItems', @@ -77,7 +87,9 @@ jobs: } suites = [] observed = {} - for path in sorted(Path('code').glob('**/target/surefire-reports/TEST-*.xml')): + reports = list(Path('code').glob('**/target/surefire-reports/TEST-*.xml')) + reports += list(Path('resources').glob('**/target/surefire-reports/TEST-*.xml')) + for path in sorted(reports): root = ET.parse(path).getroot() cases = [] for case in root.findall('testcase'): diff --git a/README.md b/README.md index 78336a36e9..faa12f8c60 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,13 @@ preserved upstream boundary. ## Current release +The source tree prepares `v0.183.329`, which closes a low-role GenericObject +read bypass for plugin capabilities in both v2-beta and the frozen v1 schemas. +Readonly/restricted clients retain resource metadata; plugin configuration is +read through its typed API. Owner/member/service storage remains unchanged. +See the [329 release note](docs/releases/orchestration-engine-0.183.329.md). +This source change is not yet a published artifact or accepted Server deployment. + The current published release is `v0.183.328`. It updates platform Jackson to `2.22.3` and the isolated WebAuthn/logging runtime to `3.2.3`, and consumes the official Cache `5.7.5` artifact. The two Jackson namespaces remain separate. @@ -101,7 +108,7 @@ bash scripts/check-cattle-jdk25-full-package After the gate passes, package and check the release artifact: ```sh -ENGINE_VERSION=0.183.328 bash scripts/build --release +ENGINE_VERSION=0.183.329 bash scripts/build --release bash scripts/check-release-artifact dist/artifacts/cattle.jar ``` @@ -111,6 +118,23 @@ database and platform checks require isolated MariaDB/MySQL and companion services. See [COMPATIBILITY.md](COMPATIBILITY.md), [SECURITY.md](SECURITY.md), and [ORIGIN.md](ORIGIN.md) for those boundaries and source provenance. +For a deliberate frozen-schema source migration, first run +`GenericObjectAuthOverlayTest` with the supported Maven/JDK toolchain. Use its +Surefire `java.class.path` property to run +From the repository root, run +`java --class-path scripts/java/UpdateFrozenGenericObjectSchemas.java`. +The one-time producer accepts no path arguments, requires the reviewed 328 +snapshot SHA-256 values before deserialization, and rejects unexpected classes +with a bounded serialization filter. `--check-filter` verifies the current two +role snapshots and rejects a graph with a deserialization callback without +executing it; it does not write files. Already migrated snapshots are rejected +by the migration path. +The helper applies only the two declared field denials to the existing v1 role +snapshots, checks the persisted schema contract for unrelated drift, and then +writes `readonly.ser` and `restricted.ser`. Run +`FrozenGenericObjectRoleSchemaTest` afterwards. It is an offline source-generation +step, never a deployed-runtime patch. + ## Language and licensing The web console supplies user-facing translations. API fields, persisted diff --git a/code/framework/api-pub-sub-jetty/pom.xml b/code/framework/api-pub-sub-jetty/pom.xml index 127fdb75c9..6837ac40ed 100644 --- a/code/framework/api-pub-sub-jetty/pom.xml +++ b/code/framework/api-pub-sub-jetty/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/framework/api-pub-sub/pom.xml b/code/framework/api-pub-sub/pom.xml index 65d17c4a4e..ff78e3e8b9 100644 --- a/code/framework/api-pub-sub/pom.xml +++ b/code/framework/api-pub-sub/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/framework/api/pom.xml b/code/framework/api/pom.xml index 5a4b086333..14d87e0ba0 100644 --- a/code/framework/api/pom.xml +++ b/code/framework/api/pom.xml @@ -4,7 +4,7 @@ cattle-parent io.cattle - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/framework/archaius/pom.xml b/code/framework/archaius/pom.xml index ad5ac3620f..fd11c24d2a 100644 --- a/code/framework/archaius/pom.xml +++ b/code/framework/archaius/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-meta-parent - 0.183.328 + 0.183.329 ../../meta-parent/pom.xml diff --git a/code/framework/async/pom.xml b/code/framework/async/pom.xml index 78b00ea6a0..90f4f1af0f 100644 --- a/code/framework/async/pom.xml +++ b/code/framework/async/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/framework/auditing/pom.xml b/code/framework/auditing/pom.xml index d6f1a698e7..794c5f0dde 100644 --- a/code/framework/auditing/pom.xml +++ b/code/framework/auditing/pom.xml @@ -4,7 +4,7 @@ cattle-parent io.cattle - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/framework/db-loader/pom.xml b/code/framework/db-loader/pom.xml index 61ca3a264b..4de2f090e9 100644 --- a/code/framework/db-loader/pom.xml +++ b/code/framework/db-loader/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/framework/deferred/pom.xml b/code/framework/deferred/pom.xml index 9fbf16ad91..dd2a0fc3fc 100644 --- a/code/framework/deferred/pom.xml +++ b/code/framework/deferred/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/framework/encryption/pom.xml b/code/framework/encryption/pom.xml index 1c4810719e..68fefe8e68 100644 --- a/code/framework/encryption/pom.xml +++ b/code/framework/encryption/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/framework/engine/pom.xml b/code/framework/engine/pom.xml index 3bd8feaaae..cd18c3739c 100644 --- a/code/framework/engine/pom.xml +++ b/code/framework/engine/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/framework/eventing/pom.xml b/code/framework/eventing/pom.xml index d0209a5dc4..3fc4bb586a 100644 --- a/code/framework/eventing/pom.xml +++ b/code/framework/eventing/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/framework/events/pom.xml b/code/framework/events/pom.xml index baa5f84e59..c57596ebd3 100644 --- a/code/framework/events/pom.xml +++ b/code/framework/events/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/framework/extension-spring/pom.xml b/code/framework/extension-spring/pom.xml index bb31759c52..b968d564c1 100644 --- a/code/framework/extension-spring/pom.xml +++ b/code/framework/extension-spring/pom.xml @@ -4,7 +4,7 @@ cattle-parent io.cattle - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/framework/extension/pom.xml b/code/framework/extension/pom.xml index b251c32eae..464eb12f5b 100644 --- a/code/framework/extension/pom.xml +++ b/code/framework/extension/pom.xml @@ -4,7 +4,7 @@ cattle-parent io.cattle - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/framework/java-server/pom.xml b/code/framework/java-server/pom.xml index 4f3ff8994b..bce836552e 100644 --- a/code/framework/java-server/pom.xml +++ b/code/framework/java-server/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/framework/jmx/pom.xml b/code/framework/jmx/pom.xml index 0a247fa563..7478e65308 100644 --- a/code/framework/jmx/pom.xml +++ b/code/framework/jmx/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/framework/jooq/pom.xml b/code/framework/jooq/pom.xml index 5741961d88..81ee08f8ae 100644 --- a/code/framework/jooq/pom.xml +++ b/code/framework/jooq/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/framework/json/pom.xml b/code/framework/json/pom.xml index 67a1e0b6fe..abbc8b2632 100644 --- a/code/framework/json/pom.xml +++ b/code/framework/json/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/framework/launcher/pom.xml b/code/framework/launcher/pom.xml index d430fe2309..e283623767 100644 --- a/code/framework/launcher/pom.xml +++ b/code/framework/launcher/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/framework/lock/pom.xml b/code/framework/lock/pom.xml index a6fb652173..a234ba5612 100644 --- a/code/framework/lock/pom.xml +++ b/code/framework/lock/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/framework/logback/pom.xml b/code/framework/logback/pom.xml index 9990b83527..65c2716acb 100644 --- a/code/framework/logback/pom.xml +++ b/code/framework/logback/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-meta-parent - 0.183.328 + 0.183.329 ../../meta-parent/pom.xml diff --git a/code/framework/managed-context/pom.xml b/code/framework/managed-context/pom.xml index f2373f1509..195c02bbd5 100644 --- a/code/framework/managed-context/pom.xml +++ b/code/framework/managed-context/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/framework/metrics/pom.xml b/code/framework/metrics/pom.xml index 7cdd24fad8..d02ec9f844 100644 --- a/code/framework/metrics/pom.xml +++ b/code/framework/metrics/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/framework/module/pom.xml b/code/framework/module/pom.xml index 4ddd3d4462..32423e40b3 100644 --- a/code/framework/module/pom.xml +++ b/code/framework/module/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/framework/object/pom.xml b/code/framework/object/pom.xml index f6b6c68d2d..363ff179f2 100644 --- a/code/framework/object/pom.xml +++ b/code/framework/object/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/framework/pool/pom.xml b/code/framework/pool/pom.xml index 27374c921d..6d7fb5d0c2 100644 --- a/code/framework/pool/pom.xml +++ b/code/framework/pool/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/framework/resource-monitor/pom.xml b/code/framework/resource-monitor/pom.xml index d558ab39f2..3281175d30 100644 --- a/code/framework/resource-monitor/pom.xml +++ b/code/framework/resource-monitor/pom.xml @@ -4,7 +4,7 @@ cattle-parent io.cattle - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/framework/schema/pom.xml b/code/framework/schema/pom.xml index 6a67489b51..329af7ff57 100644 --- a/code/framework/schema/pom.xml +++ b/code/framework/schema/pom.xml @@ -4,7 +4,7 @@ cattle-parent io.cattle - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/framework/schema/src/test/java/io/cattle/platform/schema/processor/GenericObjectAuthOverlayTest.java b/code/framework/schema/src/test/java/io/cattle/platform/schema/processor/GenericObjectAuthOverlayTest.java new file mode 100644 index 0000000000..f2b8097bd3 --- /dev/null +++ b/code/framework/schema/src/test/java/io/cattle/platform/schema/processor/GenericObjectAuthOverlayTest.java @@ -0,0 +1,137 @@ +package io.cattle.platform.schema.processor; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; + +import com.fasterxml.jackson.databind.ObjectMapper; +import io.github.ibuildthecloud.gdapi.factory.SchemaFactory; +import io.github.ibuildthecloud.gdapi.id.IdFormatter; +import io.github.ibuildthecloud.gdapi.model.impl.FieldImpl; +import io.github.ibuildthecloud.gdapi.model.impl.SchemaImpl; +import io.github.ibuildthecloud.gdapi.model.impl.WrappedResource; +import java.lang.reflect.Proxy; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.Map; +import org.junit.Test; + +/** The generic storage API must not bypass a plugin's low-role projection. */ +public class GenericObjectAuthOverlayTest { + private final Path schemas = Paths.get("../../../resources/content/schema"); + private final SchemaImpl parent = base("genericObject", null); + private final SchemaFactory factory = (SchemaFactory) Proxy.newProxyInstance( + SchemaFactory.class.getClassLoader(), new Class[] {SchemaFactory.class}, + (proxy, method, args) -> "getSchema".equals(method.getName()) + && "genericObject".equals(args[0]) ? parent : null); + private final IdFormatter ids = (IdFormatter) Proxy.newProxyInstance( + IdFormatter.class.getClassLoader(), new Class[] {IdFormatter.class}, + (proxy, method, args) -> "formatId".equals(method.getName()) ? args[1] : null); + + private SchemaImpl base(String type, String parentType) { + SchemaImpl schema = new SchemaImpl(); + schema.setId(type); + schema.setParent(parentType); + for (String name : Arrays.asList("name", "kind", "accountId", "state", "key", "resourceData", + "status", "image", "labels", "mode")) { + FieldImpl field = new FieldImpl(); + field.setName(name); + field.setType("resourceData".equals(name) ? "map[json]" : "string"); + schema.getResourceFields().put(name, field); + } + return schema; + } + + private void overlay(SchemaImpl schema, String... files) throws Exception { + AuthOverlayPostProcessor processor = new AuthOverlayPostProcessor(); + for (String file : files) { + Map document = new ObjectMapper().readValue(schemas.resolve(file).toFile(), Map.class); + processor.load((Map) document.get("authorize")); + } + processor.postProcess(schema, factory); + } + + private SchemaImpl projected(String type, String role) throws Exception { + SchemaImpl schema = base(type, "genericObject".equals(type) ? null : "genericObject"); + // The low-role processor is applied after the parent project factory, + // not merged into the parent's permissions table. + overlay(schema, "user/user-auth.json", "project/project-auth.json"); + if (role != null) { + overlay(schema, role + "/" + role + ".json"); + } + return schema; + } + + private Map response(SchemaImpl schema) { + Map fields = new LinkedHashMap(); + fields.put("name", "receiver-fixture"); + fields.put("kind", "webhookReceiver"); + fields.put("accountId", "project-fixture"); + fields.put("state", "active"); + fields.put("status", "complete"); + fields.put("image", "example.invalid/test:1"); + fields.put("labels", "test-label"); + fields.put("mode", "pull"); + fields.put("key", "test-capability"); + Map data = new LinkedHashMap(); + data.put("url", "https://example.invalid/endpoint?key=test-capability"); + data.put("config", "plugin-owned-configuration"); + fields.put("resourceData", data); + return new WrappedResource(ids, factory, schema, null, fields, null, "GET").getFields(); + } + + private void assertLowRole(SchemaImpl schema) { + assertFalse(schema.getResourceFields().containsKey("key")); + assertFalse(schema.getResourceFields().containsKey("resourceData")); + Map result = response(schema); + assertFalse(result.containsKey("key")); + assertFalse(result.containsKey("resourceData")); + assertEquals("receiver-fixture", result.get("name")); + assertEquals("webhookReceiver", result.get("kind")); + assertEquals("project-fixture", result.get("accountId")); + assertEquals("active", result.get("state")); + } + + @Test + public void lowRolesHideCapabilitiesAtTheSharedResponseBoundary() throws Exception { + for (String role : Arrays.asList("read-user", "restricted-user")) { + assertLowRole(projected("genericObject", role)); + } + } + + @Test + public void inheritedStorageFieldsCannotReintroduceCapabilities() throws Exception { + for (String role : Arrays.asList("read-user", "restricted-user")) { + assertLowRole(projected("pluginObject", role)); + assertLowRole(projected("register", role)); + } + } + + @Test + public void privilegedProjectClientsKeepPluginStorage() throws Exception { + SchemaImpl schema = projected("genericObject", null); + assertTrue(schema.getResourceFields().containsKey("key")); + assertTrue(schema.getResourceFields().containsKey("resourceData")); + Map result = response(schema); + assertEquals("test-capability", result.get("key")); + assertTrue(result.get("resourceData") instanceof Map); + } + + @Test + public void pullTaskStorageRemainsPrivateWithoutRemovingTypedStatus() throws Exception { + for (String role : Arrays.asList("read-user", "restricted-user")) { + SchemaImpl schema = projected("pullTask", role); + assertFalse(schema.getResourceFields().containsKey("key")); + assertFalse(schema.getResourceFields().containsKey("resourceData")); + assertTrue(schema.getResourceFields().containsKey("kind")); + assertTrue(schema.getResourceFields().containsKey("state")); + Map result = response(schema); + assertEquals("complete", result.get("status")); + assertEquals("example.invalid/test:1", result.get("image")); + assertEquals("test-label", result.get("labels")); + assertEquals("pull", result.get("mode")); + } + } +} diff --git a/code/framework/server/pom.xml b/code/framework/server/pom.xml index 62ee69471f..35d6f444d0 100644 --- a/code/framework/server/pom.xml +++ b/code/framework/server/pom.xml @@ -4,7 +4,7 @@ cattle-meta-parent io.cattle - 0.183.328 + 0.183.329 ../../meta-parent/pom.xml diff --git a/code/framework/spring/pom.xml b/code/framework/spring/pom.xml index 847d3e0c2d..b89ec08da8 100644 --- a/code/framework/spring/pom.xml +++ b/code/framework/spring/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/framework/system-task/pom.xml b/code/framework/system-task/pom.xml index 211022d386..968064bec3 100644 --- a/code/framework/system-task/pom.xml +++ b/code/framework/system-task/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/framework/token/pom.xml b/code/framework/token/pom.xml index 8854e7f7bf..58b4195033 100644 --- a/code/framework/token/pom.xml +++ b/code/framework/token/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/framework/utils/pom.xml b/code/framework/utils/pom.xml index 6f2da549cb..1310372727 100644 --- a/code/framework/utils/pom.xml +++ b/code/framework/utils/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/iaas/agent-instance/pom.xml b/code/iaas/agent-instance/pom.xml index 4352169450..d11713003b 100644 --- a/code/iaas/agent-instance/pom.xml +++ b/code/iaas/agent-instance/pom.xml @@ -4,7 +4,7 @@ cattle-parent io.cattle - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/iaas/agent-server/pom.xml b/code/iaas/agent-server/pom.xml index cb4533443e..89a90ed9c2 100644 --- a/code/iaas/agent-server/pom.xml +++ b/code/iaas/agent-server/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/iaas/agent/pom.xml b/code/iaas/agent/pom.xml index 82e3570b68..e98234dbd5 100644 --- a/code/iaas/agent/pom.xml +++ b/code/iaas/agent/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/iaas/allocator/pom.xml b/code/iaas/allocator/pom.xml index b1554f586d..9e495069af 100644 --- a/code/iaas/allocator/pom.xml +++ b/code/iaas/allocator/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/iaas/api-logic/pom.xml b/code/iaas/api-logic/pom.xml index 2e8eb62e41..0f4bf4634c 100644 --- a/code/iaas/api-logic/pom.xml +++ b/code/iaas/api-logic/pom.xml @@ -4,7 +4,7 @@ cattle-parent io.cattle - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/iaas/archaius-management/pom.xml b/code/iaas/archaius-management/pom.xml index 4e85f1bb84..bc93c65417 100644 --- a/code/iaas/archaius-management/pom.xml +++ b/code/iaas/archaius-management/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/iaas/auth-logic/pom.xml b/code/iaas/auth-logic/pom.xml index 9e541cb00f..b94cfce7f6 100644 --- a/code/iaas/auth-logic/pom.xml +++ b/code/iaas/auth-logic/pom.xml @@ -4,7 +4,7 @@ cattle-parent io.cattle - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/iaas/bootstrap/pom.xml b/code/iaas/bootstrap/pom.xml index 1bd2e65bf9..fb5671c925 100644 --- a/code/iaas/bootstrap/pom.xml +++ b/code/iaas/bootstrap/pom.xml @@ -4,7 +4,7 @@ cattle-parent io.cattle - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/iaas/config-item/api/pom.xml b/code/iaas/config-item/api/pom.xml index ef45191dcc..f3ad97e8d0 100644 --- a/code/iaas/config-item/api/pom.xml +++ b/code/iaas/config-item/api/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../../parent/pom.xml diff --git a/code/iaas/config-item/common/pom.xml b/code/iaas/config-item/common/pom.xml index 297a1631dc..169fd7d1c2 100644 --- a/code/iaas/config-item/common/pom.xml +++ b/code/iaas/config-item/common/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../../parent/pom.xml diff --git a/code/iaas/config-item/server/pom.xml b/code/iaas/config-item/server/pom.xml index b22ba12d8b..99370dc09a 100644 --- a/code/iaas/config-item/server/pom.xml +++ b/code/iaas/config-item/server/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../../parent/pom.xml diff --git a/code/iaas/engine-jooq/pom.xml b/code/iaas/engine-jooq/pom.xml index 3bcd1ac9e1..69ce2ba412 100644 --- a/code/iaas/engine-jooq/pom.xml +++ b/code/iaas/engine-jooq/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/iaas/events/pom.xml b/code/iaas/events/pom.xml index c341f18a31..1e33aba6f4 100644 --- a/code/iaas/events/pom.xml +++ b/code/iaas/events/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/iaas/external-handler/pom.xml b/code/iaas/external-handler/pom.xml index f850e3061a..98ac47e63a 100644 --- a/code/iaas/external-handler/pom.xml +++ b/code/iaas/external-handler/pom.xml @@ -4,7 +4,7 @@ cattle-parent io.cattle - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/iaas/ha/pom.xml b/code/iaas/ha/pom.xml index f65cc3a2fa..cf84982670 100644 --- a/code/iaas/ha/pom.xml +++ b/code/iaas/ha/pom.xml @@ -4,7 +4,7 @@ cattle-parent io.cattle - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/iaas/healthcheck/pom.xml b/code/iaas/healthcheck/pom.xml index a30c264090..708dc6fa1c 100644 --- a/code/iaas/healthcheck/pom.xml +++ b/code/iaas/healthcheck/pom.xml @@ -4,7 +4,7 @@ cattle-parent io.cattle - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/iaas/labels/pom.xml b/code/iaas/labels/pom.xml index d1886d20a5..7355825de8 100644 --- a/code/iaas/labels/pom.xml +++ b/code/iaas/labels/pom.xml @@ -4,7 +4,7 @@ cattle-parent io.cattle - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/iaas/logic-common/pom.xml b/code/iaas/logic-common/pom.xml index f48905a6e4..593f912b16 100644 --- a/code/iaas/logic-common/pom.xml +++ b/code/iaas/logic-common/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/iaas/logic/pom.xml b/code/iaas/logic/pom.xml index cbf41e034f..300646ddef 100644 --- a/code/iaas/logic/pom.xml +++ b/code/iaas/logic/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/iaas/metadata/pom.xml b/code/iaas/metadata/pom.xml index ea96c2f2a7..040876d02a 100644 --- a/code/iaas/metadata/pom.xml +++ b/code/iaas/metadata/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/iaas/model/pom.xml b/code/iaas/model/pom.xml index 68407581a7..3bd25d0168 100644 --- a/code/iaas/model/pom.xml +++ b/code/iaas/model/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/iaas/resource-pool/pom.xml b/code/iaas/resource-pool/pom.xml index 5c7e7cf91d..f0629558b3 100644 --- a/code/iaas/resource-pool/pom.xml +++ b/code/iaas/resource-pool/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/iaas/service-discovery/api/pom.xml b/code/iaas/service-discovery/api/pom.xml index e5a2799e51..b47dba16ee 100644 --- a/code/iaas/service-discovery/api/pom.xml +++ b/code/iaas/service-discovery/api/pom.xml @@ -4,7 +4,7 @@ cattle-parent io.cattle - 0.183.328 + 0.183.329 ../../../parent/pom.xml diff --git a/code/iaas/service-discovery/server/pom.xml b/code/iaas/service-discovery/server/pom.xml index c3b012215c..104fe4d760 100644 --- a/code/iaas/service-discovery/server/pom.xml +++ b/code/iaas/service-discovery/server/pom.xml @@ -4,7 +4,7 @@ cattle-parent io.cattle - 0.183.328 + 0.183.329 ../../../parent/pom.xml diff --git a/code/iaas/ssh-common/pom.xml b/code/iaas/ssh-common/pom.xml index 5cad182a86..b3522603fe 100644 --- a/code/iaas/ssh-common/pom.xml +++ b/code/iaas/ssh-common/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/iaas/storage-service/pom.xml b/code/iaas/storage-service/pom.xml index b3f2b33fbc..dbd8d5f162 100644 --- a/code/iaas/storage-service/pom.xml +++ b/code/iaas/storage-service/pom.xml @@ -4,7 +4,7 @@ cattle-parent io.cattle - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/iaas/task-jooq/pom.xml b/code/iaas/task-jooq/pom.xml index 38e74054df..29328a3bf7 100644 --- a/code/iaas/task-jooq/pom.xml +++ b/code/iaas/task-jooq/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/implementation/activity-log/pom.xml b/code/implementation/activity-log/pom.xml index 257a239a75..dac415e424 100644 --- a/code/implementation/activity-log/pom.xml +++ b/code/implementation/activity-log/pom.xml @@ -5,7 +5,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/implementation/agent-instance-impl/pom.xml b/code/implementation/agent-instance-impl/pom.xml index df51b05e74..1a1b15a282 100644 --- a/code/implementation/agent-instance-impl/pom.xml +++ b/code/implementation/agent-instance-impl/pom.xml @@ -3,7 +3,7 @@ cattle-parent io.cattle - 0.183.328 + 0.183.329 ../../parent/pom.xml cattle-agent-instance-impl diff --git a/code/implementation/docker/api/pom.xml b/code/implementation/docker/api/pom.xml index c852088b8a..36ed44941b 100644 --- a/code/implementation/docker/api/pom.xml +++ b/code/implementation/docker/api/pom.xml @@ -5,7 +5,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../../parent/pom.xml diff --git a/code/implementation/docker/common/pom.xml b/code/implementation/docker/common/pom.xml index 20e2496010..0c763f3b6e 100644 --- a/code/implementation/docker/common/pom.xml +++ b/code/implementation/docker/common/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../../parent/pom.xml diff --git a/code/implementation/docker/compute/pom.xml b/code/implementation/docker/compute/pom.xml index 005c918ce0..c166000654 100644 --- a/code/implementation/docker/compute/pom.xml +++ b/code/implementation/docker/compute/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../../parent/pom.xml diff --git a/code/implementation/docker/machine/pom.xml b/code/implementation/docker/machine/pom.xml index fff87ad881..26eb011662 100644 --- a/code/implementation/docker/machine/pom.xml +++ b/code/implementation/docker/machine/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../../parent/pom.xml diff --git a/code/implementation/docker/storage/pom.xml b/code/implementation/docker/storage/pom.xml index 4f24761f2f..a0f4805b8d 100644 --- a/code/implementation/docker/storage/pom.xml +++ b/code/implementation/docker/storage/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../../parent/pom.xml @@ -21,12 +21,12 @@ io.cattle cattle-docker-common - 0.183.328 + 0.183.329 io.cattle cattle-iaas-allocator - 0.183.328 + 0.183.329 diff --git a/code/implementation/extension-api/pom.xml b/code/implementation/extension-api/pom.xml index b052faffe6..7126313e64 100644 --- a/code/implementation/extension-api/pom.xml +++ b/code/implementation/extension-api/pom.xml @@ -3,7 +3,7 @@ cattle-parent io.cattle - 0.183.328 + 0.183.329 ../../parent/pom.xml cattle-extension-api diff --git a/code/implementation/hazelcast/common/pom.xml b/code/implementation/hazelcast/common/pom.xml index facdafddd6..0558dd5945 100644 --- a/code/implementation/hazelcast/common/pom.xml +++ b/code/implementation/hazelcast/common/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../../parent/pom.xml diff --git a/code/implementation/hazelcast/eventing/pom.xml b/code/implementation/hazelcast/eventing/pom.xml index 07ba98745b..6ac3b82944 100644 --- a/code/implementation/hazelcast/eventing/pom.xml +++ b/code/implementation/hazelcast/eventing/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../../parent/pom.xml diff --git a/code/implementation/hazelcast/lock/pom.xml b/code/implementation/hazelcast/lock/pom.xml index 5700f8c2ba..1cedc4e20a 100644 --- a/code/implementation/hazelcast/lock/pom.xml +++ b/code/implementation/hazelcast/lock/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../../parent/pom.xml diff --git a/code/implementation/host-api/pom.xml b/code/implementation/host-api/pom.xml index 07be1b8caa..6842b2025e 100644 --- a/code/implementation/host-api/pom.xml +++ b/code/implementation/host-api/pom.xml @@ -5,7 +5,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/implementation/host-stats/pom.xml b/code/implementation/host-stats/pom.xml index d22f2301ee..09620e73c4 100644 --- a/code/implementation/host-stats/pom.xml +++ b/code/implementation/host-stats/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/implementation/register/pom.xml b/code/implementation/register/pom.xml index 889eddf3c6..b190295d45 100644 --- a/code/implementation/register/pom.xml +++ b/code/implementation/register/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/implementation/sample-setup/pom.xml b/code/implementation/sample-setup/pom.xml index 11c11d8292..14767db3ff 100644 --- a/code/implementation/sample-setup/pom.xml +++ b/code/implementation/sample-setup/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/implementation/settings-api/pom.xml b/code/implementation/settings-api/pom.xml index 8a10b9d2c7..b2ed51b96d 100644 --- a/code/implementation/settings-api/pom.xml +++ b/code/implementation/settings-api/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/implementation/simulator/agent-connection/pom.xml b/code/implementation/simulator/agent-connection/pom.xml index 26fff2feaf..76c8fddaa2 100644 --- a/code/implementation/simulator/agent-connection/pom.xml +++ b/code/implementation/simulator/agent-connection/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../../parent/pom.xml diff --git a/code/implementation/simulator/storage/pom.xml b/code/implementation/simulator/storage/pom.xml index db80e23608..5472f84df3 100644 --- a/code/implementation/simulator/storage/pom.xml +++ b/code/implementation/simulator/storage/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../../parent/pom.xml diff --git a/code/implementation/system-stack/pom.xml b/code/implementation/system-stack/pom.xml index 6b08b149d6..ac6fef404b 100644 --- a/code/implementation/system-stack/pom.xml +++ b/code/implementation/system-stack/pom.xml @@ -5,7 +5,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/implementation/vm/pom.xml b/code/implementation/vm/pom.xml index 6c26be22e1..67e0682622 100644 --- a/code/implementation/vm/pom.xml +++ b/code/implementation/vm/pom.xml @@ -3,7 +3,7 @@ cattle-parent io.cattle - 0.183.328 + 0.183.329 ../../parent/pom.xml cattle-vm diff --git a/code/meta-parent/pom.xml b/code/meta-parent/pom.xml index 38669d5791..ad194a7bb1 100644 --- a/code/meta-parent/pom.xml +++ b/code/meta-parent/pom.xml @@ -9,7 +9,7 @@ 4.0.0 io.cattle cattle-meta-parent - 0.183.328 + 0.183.329 pom PastureStack Orchestration Engine Compatibility orchestration engine for the PastureStack server. diff --git a/code/packaging/app-config/pom.xml b/code/packaging/app-config/pom.xml index 7108c1dd37..6e9c1e9c76 100644 --- a/code/packaging/app-config/pom.xml +++ b/code/packaging/app-config/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml jar diff --git a/code/packaging/app/pom.xml b/code/packaging/app/pom.xml index 40e24b947f..5bd8581098 100644 --- a/code/packaging/app/pom.xml +++ b/code/packaging/app/pom.xml @@ -4,7 +4,7 @@ cattle-parent io.cattle - 0.183.328 + 0.183.329 ../../parent/pom.xml war diff --git a/code/packaging/bundle/pom.xml b/code/packaging/bundle/pom.xml index 6ce9d9279f..7de63641a0 100644 --- a/code/packaging/bundle/pom.xml +++ b/code/packaging/bundle/pom.xml @@ -4,7 +4,7 @@ cattle-parent io.cattle - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/packaging/dev/pom.xml b/code/packaging/dev/pom.xml index f7828b12b9..26d2bf66f7 100644 --- a/code/packaging/dev/pom.xml +++ b/code/packaging/dev/pom.xml @@ -4,7 +4,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/packaging/meta/pom.xml b/code/packaging/meta/pom.xml index e4fe63274b..834467b112 100644 --- a/code/packaging/meta/pom.xml +++ b/code/packaging/meta/pom.xml @@ -4,7 +4,7 @@ cattle-parent io.cattle - 0.183.328 + 0.183.329 ../../parent/pom.xml diff --git a/code/parent/pom.xml b/code/parent/pom.xml index 52a25b01c7..e0f7426f2e 100644 --- a/code/parent/pom.xml +++ b/code/parent/pom.xml @@ -5,7 +5,7 @@ io.cattle cattle-meta-parent ../meta-parent/pom.xml - 0.183.328 + 0.183.329 pom diff --git a/docs/releases/orchestration-engine-0.183.329.md b/docs/releases/orchestration-engine-0.183.329.md new file mode 100644 index 0000000000..ed930e8055 --- /dev/null +++ b/docs/releases/orchestration-engine-0.183.329.md @@ -0,0 +1,51 @@ +# Orchestration Engine 0.183.329 + +## Behavior + +Readonly and restricted project roles could read a Receiver's stored capability +through GenericObject even though the Receiver API omitted its execution URL. +The QA reproduction on Server 1.6.497 / Engine 0.183.328 confirmed an exact v1 +GET returned a nonempty key and a URL matching the owner's capability hash. +The execution endpoint was not called. + +The fix uses the existing authorization boundary: the two low-role schema +overlays deny `genericObject.key` and `genericObject.resourceData`. This also +applies to inherited storage fields. It does not hardcode a plugin kind, parse +URLs, change hook execution, or introduce another secret-storage system. +The frozen v1 readonly/restricted schemas receive the same field denials. + +Resource metadata stays readable. Receiver configuration remains available +through its typed plugin API, with execution URLs still hidden for low roles. +Owner/member/service clients retain plugin storage and normal Receiver writes. +Consumers that directly read opaque GenericObject data with a low-role token +must use the authorized typed API instead. Project/identity authorization, +MFA, cookie/session ownership, and unrelated write policy are unchanged. + +## Focused evidence + +- Before the fix: 4 overlay tests, 2 expected failures, 0 errors/skips. +- After the fix: all 4 overlay/response-projection tests and 2 actual frozen-v1 + tests pass with Maven 3.9.16 / JDK 25.0.4. +- The offline producer checks persisted schema equality: only key/resourceData + are removed from GenericObject and its inherited Register schema in each + low-role snapshot; unrelated schema/method/action/filter/field data is retained. +- Owner/member/project/service frozen schemas retain both fields. +- The package gate verifies the reviewed JSON denials and exact frozen role + bytes inside the actual WAR, preventing a JSON-only or stale-v1 publication. +- The offline snapshot producer rejects path arguments and unreviewed input + hashes, and uses a bounded exact-class deserialization filter. The filter + accepts both current role snapshots and rejects an unexpected graph before + its deserialization callback executes. An initial CodeQL candidate detected + the former command-line-path/unfiltered producer; that failed run is retained, + not treated as a passing gate. + +## Release status and recovery + +The source is prepared for the normal immutable component build/publication. +Artifact hash, source revision, CI evidence, Server consumption, and real +v1/v2-beta role/browser results will be recorded after those gates complete. +No full permission-matrix acceptance is implied by these focused tests. + +There is no database migration and no HAProxy/runtime patch. A rollback to the +previous image restores the previous schema visibility, including this +capability-read weakness; preserve existing configuration and named volumes. diff --git a/pom.xml b/pom.xml index f1e2b71c3e..3c8d58a8ea 100644 --- a/pom.xml +++ b/pom.xml @@ -3,7 +3,7 @@ io.cattle cattle-parent - 0.183.328 + 0.183.329 code/parent/pom.xml cattle diff --git a/resources/content/schema/read-user/read-user.json b/resources/content/schema/read-user/read-user.json index 4afc824c11..fa178b0a5e 100644 --- a/resources/content/schema/read-user/read-user.json +++ b/resources/content/schema/read-user/read-user.json @@ -3,6 +3,8 @@ ".*\\.resourceActions\\..*": "", ".*\\.uuid": "r", "registrationToken": "", + "genericObject.key": "", + "genericObject.resourceData": "", "container.resourceActions.logs": "c", "instance.environment": "", @@ -12,4 +14,4 @@ "end" : "" } -} \ No newline at end of file +} diff --git a/resources/content/schema/restricted-user/restricted-user.json b/resources/content/schema/restricted-user/restricted-user.json index ce529c175a..340ca92aaa 100644 --- a/resources/content/schema/restricted-user/restricted-user.json +++ b/resources/content/schema/restricted-user/restricted-user.json @@ -5,6 +5,8 @@ "physicalHost": "r", "physicalHost.resourceActions\\..*": "", "registrationToken" : "", + "genericObject.key": "", + "genericObject.resourceData": "", "end" : "" } diff --git a/resources/content/schema/v1/readonly.ser b/resources/content/schema/v1/readonly.ser index 7862d61795c0ee8ab2475799ddac11a944bd20fe..7ee8b50513fd028127740e0048260b6c86e25ec6 100644 GIT binary patch delta 27393 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⪙FXSUaq_LG?A2s&Em0{=#w6)-cr#BUx^=LOLBUBQ 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%0D= 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 L;QRoT)F=KAGvQNZ diff --git a/resources/content/schema/v1/restricted.ser b/resources/content/schema/v1/restricted.ser index 6ec35d367fb3507cfb66679c37f8f66c3e2e67ee..d1328b1c08c47dd3b6ee33740f298b969d605aa5 100644 GIT binary patch delta 32358 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 delta 31979 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 cattle-parent io.cattle - 0.183.328 + 0.183.329 ../code/parent/pom.xml diff --git a/resources/src/test/java/io/cattle/platform/resources/FrozenGenericObjectRoleSchemaTest.java b/resources/src/test/java/io/cattle/platform/resources/FrozenGenericObjectRoleSchemaTest.java new file mode 100644 index 0000000000..2205937779 --- /dev/null +++ b/resources/src/test/java/io/cattle/platform/resources/FrozenGenericObjectRoleSchemaTest.java @@ -0,0 +1,62 @@ +package io.cattle.platform.resources; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; + +import io.github.ibuildthecloud.gdapi.model.Schema; +import java.io.FileInputStream; +import java.io.ObjectInputStream; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import org.junit.Test; + +/** v1 reads these files directly; JSON-only authorization fixes are insufficient. */ +public class FrozenGenericObjectRoleSchemaTest { + private Map read(String role) throws Exception { + Map result = new LinkedHashMap(); + try (ObjectInputStream input = new ObjectInputStream(new FileInputStream( + Paths.get("content", "schema", "v1", role + ".ser").toFile()))) { + for (Object item : (List) input.readObject()) { + Schema schema = Schema.class.cast(item); + result.put(schema.getId(), schema); + } + } + return result; + } + + @Test + public void lowRoleFrozenSchemasCannotRevealGenericStorageCapabilities() throws Exception { + for (String role : Arrays.asList("readonly", "restricted")) { + Map schemas = read(role); + assertNotNull(role, schemas.get("genericObject")); + for (Schema schema : schemas.values()) { + Schema current = schema; + while (current != null && !"genericObject".equals(current.getId())) { + current = schemas.get(current.getParent()); + } + if (current != null) { + assertFalse(role + "/" + schema.getId(), schema.getResourceFields().containsKey("key")); + assertFalse(role + "/" + schema.getId(), schema.getResourceFields().containsKey("resourceData")); + } + } + Schema generic = schemas.get("genericObject"); + for (String field : Arrays.asList("name", "kind", "accountId", "state")) { + assertTrue(role + "/" + field, generic.getResourceFields().containsKey(field)); + } + } + } + + @Test + public void privilegedProjectSchemasRetainPluginStorage() throws Exception { + for (String role : Arrays.asList("owner", "member", "project", "service")) { + Schema schema = read(role).get("genericObject"); + assertNotNull(role, schema); + assertTrue(role, schema.getResourceFields().containsKey("key")); + assertTrue(role, schema.getResourceFields().containsKey("resourceData")); + } + } +} diff --git a/scripts/build b/scripts/build index aee980f2b6..9f6de53a79 100755 --- a/scripts/build +++ b/scripts/build @@ -16,7 +16,7 @@ fi SOURCE_REVISION=${SOURCE_REVISION:-$(git rev-parse HEAD)} SOURCE_DATE_EPOCH=${SOURCE_DATE_EPOCH:-$(git show -s --format=%ct HEAD)} -ENGINE_VERSION=${ENGINE_VERSION:-0.183.328} +ENGINE_VERSION=${ENGINE_VERSION:-0.183.329} case "$SOURCE_REVISION" in ''|*[!0-9a-f]*) diff --git a/scripts/check-pasturestack-source b/scripts/check-pasturestack-source index bbb8ba4125..9721dee535 100755 --- a/scripts/check-pasturestack-source +++ b/scripts/check-pasturestack-source @@ -51,7 +51,7 @@ fi project_version=$(sed -n 's/^[[:space:]]*\([^<]*\)<\/version>[[:space:]]*$/\1/p' code/meta-parent/pom.xml | head -n 1) [[ "$project_version" =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]] || fail non_numeric_project_version -require_line code/meta-parent/pom.xml ' 0.183.328' +require_line code/meta-parent/pom.xml ' 0.183.329' require_line code/meta-parent/pom.xml ' 2.3.35' require_line "$iaas_api_defaults" 'auth.service.external.id.types=github_user,github_org,github_team,shibboleth_user,shibboleth_group,ldap_user,ldap_group,oidc_user,oidc_group' require_line code/meta-parent/pom.xml ' https://github.com/PastureStack/orchestration-engine' @@ -416,4 +416,4 @@ require_line README.md 'modernize the Rancher 1.6 ecosystem. It is not affiliate require_line README.md 'by Rancher Labs or SUSE.' require_line ORIGIN.md '- Preserved upstream boundary: `82d154a53f4089fecfb9f320caad826bb4f6055f`' -printf 'PASTURESTACK_SOURCE_GATE_OK version=0.183.328 runtime_sources=github_release images=digest_pinned ubuntu=26.04 ubuntu_snapshot=20260826T000000Z jdk=25.0.4 maven=3.9.16 patched_hazelcast=5.7.5 docker_cli=29.7.2 docker_host_29_8_0=exact credential_secret_capacity=mediumtext port_preflight=authoritative volume_preflight=runtime_resolution_aligned volume_preflight_project_schema=authorized volume_preflight_type_set=registered v1_hardware_schema=container-and-launchConfig network_driver_rollback=launch-config-restored stack_driver_rollback=child-launch-config-restored auth_token_session_binding=authorized-create-only auth_token_transport=bare-or-bearer-normalized auth_token_frozen_v1_schema=base-superadmin-token oidc_external_types=validated-before-mutation-owned-stable-account oidc_account_activation=sync-before-mfa oidc_v1_project_member_schema=core-options-merged-scoped oidc_identity_link_owner=explicit-and-verified legacy_token_link_repair=exact-match-only oidc_required_local_recovery=active-admin-only default_project=shared-idempotent-role-preserving,atomic-identity-set oidc_restricted_project_membership=stable-account-aware-required-allowlist-only mfa_policy_confirmation=actor-purpose-digest-single-use auth_config_proxy_identity=caller-platform-credential project_member_collection_acl=requested-project-checked-before-load project_template_v1_public=readonly-frozen-field-merged network_purge=retry-removing dev_artifact=forbidden\n' +printf 'PASTURESTACK_SOURCE_GATE_OK version=0.183.329 runtime_sources=github_release images=digest_pinned ubuntu=26.04 ubuntu_snapshot=20260826T000000Z jdk=25.0.4 maven=3.9.16 patched_hazelcast=5.7.5 docker_cli=29.7.2 docker_host_29_8_0=exact credential_secret_capacity=mediumtext port_preflight=authoritative volume_preflight=runtime_resolution_aligned volume_preflight_project_schema=authorized volume_preflight_type_set=registered v1_hardware_schema=container-and-launchConfig network_driver_rollback=launch-config-restored stack_driver_rollback=child-launch-config-restored auth_token_session_binding=authorized-create-only auth_token_transport=bare-or-bearer-normalized auth_token_frozen_v1_schema=base-superadmin-token oidc_external_types=validated-before-mutation-owned-stable-account oidc_account_activation=sync-before-mfa oidc_v1_project_member_schema=core-options-merged-scoped oidc_identity_link_owner=explicit-and-verified legacy_token_link_repair=exact-match-only oidc_required_local_recovery=active-admin-only default_project=shared-idempotent-role-preserving,atomic-identity-set oidc_restricted_project_membership=stable-account-aware-required-allowlist-only mfa_policy_confirmation=actor-purpose-digest-single-use auth_config_proxy_identity=caller-platform-credential project_member_collection_acl=requested-project-checked-before-load project_template_v1_public=readonly-frozen-field-merged network_purge=retry-removing dev_artifact=forbidden\n' diff --git a/scripts/check-release-artifact b/scripts/check-release-artifact index 05de760b45..f7e5fd72b9 100755 --- a/scripts/check-release-artifact +++ b/scripts/check-release-artifact @@ -4,7 +4,7 @@ set -euo pipefail cd "$(dirname "$0")/.." artifact=${1:-dist/artifacts/cattle.jar} -expected_version=${EXPECTED_ENGINE_VERSION:-0.183.328} +expected_version=${EXPECTED_ENGINE_VERSION:-0.183.329} test -f "$artifact" artifact=$(realpath "$artifact") @@ -172,6 +172,18 @@ for frozen_token_schema in base.ser superadmin.ser token.ser; do unzip -p "$workdir/$resources_entry" "schema/v1/$frozen_token_schema" | grep -aF 'clientSessionId' >/dev/null done +for role in read-user restricted-user; do + for field in key resourceData; do + unzip -p "$workdir/$resources_entry" "schema/$role/$role.json" | + grep -F "\"genericObject.$field\": \"\"" >/dev/null + done +done +# v1 bypasses the JSON overlay. Require the exact reviewed frozen role artifacts, +# not a string marker that could also occur in another schema in the same file. +for role in readonly restricted; do + unzip -p "$workdir/$resources_entry" "schema/v1/$role.ser" > "$workdir/$role.ser" + cmp "resources/content/schema/v1/$role.ser" "$workdir/$role.ser" +done unzip -p "$workdir/$resources_entry" cattle-global.properties | grep -Fx 'auth.service.external.id.types=github_user,github_org,github_team,shibboleth_user,shibboleth_group,ldap_user,ldap_group,oidc_user,oidc_group' >/dev/null diff --git a/scripts/java/UpdateFrozenGenericObjectSchemas.java b/scripts/java/UpdateFrozenGenericObjectSchemas.java new file mode 100644 index 0000000000..456c59ef0a --- /dev/null +++ b/scripts/java/UpdateFrozenGenericObjectSchemas.java @@ -0,0 +1,208 @@ +import com.fasterxml.jackson.databind.JsonNode; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import io.cattle.platform.schema.processor.AuthOverlayPostProcessor; +import io.github.ibuildthecloud.gdapi.factory.SchemaFactory; +import io.github.ibuildthecloud.gdapi.factory.impl.SchemaPostProcessor; +import io.github.ibuildthecloud.gdapi.factory.impl.SubSchemaFactory; +import io.github.ibuildthecloud.gdapi.model.Schema; +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InvalidClassException; +import java.io.ObjectInputFilter; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.lang.reflect.Proxy; +import java.nio.file.Files; +import java.nio.file.LinkOption; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.security.MessageDigest; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; + +/** Offline source migration: preserve v1 snapshots, apply only shipped low-role rules. */ +class UpdateFrozenGenericObjectSchemas { + // This one-time migration accepts only the reviewed 0.183.328 snapshots. + // Neither a caller-provided path nor an arbitrary serialized graph is input. + private static final ObjectInputFilter SCHEMA_FILTER = ObjectInputFilter.Config.createFilter( + "maxdepth=80;maxrefs=100000;maxbytes=2097152;maxarray=100000;" + + "io.github.ibuildthecloud.gdapi.model.impl.SchemaImpl;" + + "io.github.ibuildthecloud.gdapi.model.impl.FieldImpl;" + + "io.github.ibuildthecloud.gdapi.model.Action;" + + "io.github.ibuildthecloud.gdapi.model.Filter;" + + "io.github.ibuildthecloud.gdapi.model.FieldType;" + + "java.lang.String;java.lang.Boolean;java.lang.Long;java.lang.Number;" + + "java.lang.Enum;java.lang.Object;java.util.ArrayList;java.util.HashMap;" + + "java.util.LinkedHashMap;java.util.Map$Entry;!*"); + + private static ObjectInputStream schemaInput(byte[] bytes) throws Exception { + ObjectInputStream input = new ObjectInputStream(new ByteArrayInputStream(bytes)); + input.setObjectInputFilter(SCHEMA_FILTER); + return input; + } + + private static byte[] reviewedSnapshot(Path path, String role) throws Exception { + if (!Files.isRegularFile(path, LinkOption.NOFOLLOW_LINKS) || Files.size(path) > 2097152) { + throw new IllegalArgumentException("Expected regular source snapshot: " + role); + } + byte[] bytes = Files.readAllBytes(path); + String expected = "readonly".equals(role) + ? "9be2084fabdb9f70e664009d98ca4cbfdc456645c3ad4faf683c5a8af5f83e88" + : "2394998f427a3868d0053c445c7f2b1c690fae4e9666174d5ee4ee938f58e96d"; + if (!java.util.HexFormat.of().formatHex(MessageDigest.getInstance("SHA-256").digest(bytes)).equals(expected)) { + throw new IllegalArgumentException("Unreviewed or already migrated source snapshot: " + role); + } + return bytes; + } + + private static class UnexpectedGraph implements Serializable { + private static final long serialVersionUID = 1L; + static boolean executed; + + private void readObject(ObjectInputStream input) throws IOException, ClassNotFoundException { + executed = true; + input.defaultReadObject(); + } + } + + private static void checkFilter() throws Exception { + for (String role : Arrays.asList("readonly", "restricted")) { + byte[] bytes = Files.readAllBytes(Paths.get("resources/content/schema/v1/" + role + ".ser")); + try (ObjectInputStream input = schemaInput(bytes)) { + List schemas = (List) input.readObject(); + if (schemas.isEmpty()) { + throw new AssertionError("Empty schema snapshot"); + } + for (Object schema : schemas) { + Schema.class.cast(schema); + } + } + } + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + try (ObjectOutputStream output = new ObjectOutputStream(bytes)) { + output.writeObject(new UnexpectedGraph()); + } + try (ObjectInputStream input = schemaInput(bytes.toByteArray())) { + input.readObject(); + throw new AssertionError("Unexpected serialized class accepted"); + } catch (InvalidClassException expected) { + if (UnexpectedGraph.executed) { + throw new AssertionError("Rejected graph executed its callback"); + } + } + System.out.println("FROZEN_SCHEMA_FILTER_OK known_roles=2 unexpected_graph_rejected=1 callback_executed=0"); + } + + private static class Overlay extends AuthOverlayPostProcessor { + void document(Map doc) { + Map declared = (Map) doc.get("authorize"); + Map changed = new LinkedHashMap(); + for (String name : Arrays.asList("genericObject.key", "genericObject.resourceData")) { + if (!"".equals(declared.get(name))) { + throw new IllegalStateException("Expected explicit field denial: " + name); + } + changed.put(name, ""); + } + load(changed); + } + } + + public static void main(String[] args) throws Exception { + if (args.length == 1 && "--check-filter".equals(args[0])) { + checkFilter(); + return; + } + if (args.length != 0) { + throw new IllegalArgumentException("Run from repository root; no path arguments accepted"); + } + Path root = Paths.get(".").toRealPath(); + ObjectMapper mapper = new ObjectMapper(); + Map outputs = new LinkedHashMap(); + for (String role : Arrays.asList("readonly", "restricted")) { + String overlay = "readonly".equals(role) ? "read-user" : "restricted-user"; + Path path = root.resolve("resources/content/schema/v1/" + role + ".ser"); + List original = new ArrayList(); + Map index = new LinkedHashMap(); + try (ObjectInputStream input = schemaInput(reviewedSnapshot(path, role))) { + for (Object item : (List) input.readObject()) { + Schema schema = Schema.class.cast(item); + original.add(schema); + index.put(schema.getId(), schema); + } + } + SchemaFactory parent = (SchemaFactory) Proxy.newProxyInstance( + SchemaFactory.class.getClassLoader(), new Class[] {SchemaFactory.class}, + (proxy, method, values) -> { + if ("listSchemas".equals(method.getName())) { + return original; + } + return "getSchema".equals(method.getName()) ? index.get(values[0]) : null; + }); + Overlay auth = new Overlay(); + auth.document(mapper.readValue(root.resolve("resources/content/schema/" + overlay + "/" + + overlay + ".json").toFile(), Map.class)); + SubSchemaFactory factory = new SubSchemaFactory(); + factory.setId(role); + factory.setSchemaFactory(parent); + factory.setPostProcessors(Arrays.asList(auth)); + factory.init(); + ByteArrayOutputStream bytes = new ByteArrayOutputStream(); + try (ObjectOutputStream output = new ObjectOutputStream(bytes)) { + output.writeObject(factory.listSchemas()); + } + // Compare the persisted contract, not non-serializable ResourceImpl + // constructor state (type/baseType) on the in-memory factory copy. + List result = new ArrayList(); + try (ObjectInputStream input = schemaInput(bytes.toByteArray())) { + for (Object item : (List) input.readObject()) { + result.add(Schema.class.cast(item)); + } + } + if (result.size() != original.size()) { + throw new IllegalStateException("Unexpected schema removal: " + role); + } + int changed = 0; + for (Schema schema : result) { + Schema before = index.get(schema.getId()); + JsonNode expected = mapper.valueToTree(before); + Schema ancestor = before; + while (ancestor != null && !"genericObject".equals(ancestor.getId())) { + ancestor = index.get(ancestor.getParent()); + } + if (ancestor != null) { + ObjectNode fields = (ObjectNode) expected.get("resourceFields"); + if (fields.remove("key") != null | fields.remove("resourceData") != null) { + changed++; + } + } + JsonNode actual = mapper.valueToTree(schema); + if (!expected.equals(actual)) { + expected.fieldNames().forEachRemaining(name -> { + if (!expected.get(name).equals(actual.get(name))) { + System.err.println("Changed schema property: " + name); + } + }); + throw new IllegalStateException("Unrelated frozen schema drift: " + role + "/" + schema.getId()); + } + } + if (changed == 0) { + throw new IllegalStateException("Already migrated or missing generic storage: " + role); + } + outputs.put(path, bytes.toByteArray()); + System.out.println(role + ": verified field-only changes in " + changed + " schemas"); + } + // Validate both roles before writing either source artifact. + for (Map.Entry entry : outputs.entrySet()) { + try (FileOutputStream output = new FileOutputStream(entry.getKey().toFile())) { + output.write(entry.getValue()); + } + } + } +}