From 07107125b384db545ca39f26f8667468ae3fe30b Mon Sep 17 00:00:00 2001
From: chen21019 <19357113+chen21019@users.noreply.github.com>
Date: Sun, 27 Sep 2026 17:20:22 +0800
Subject: [PATCH] fix(api): expose public template state in frozen v1 user
schema
---
COMPATIBILITY.md | 13 +--
README.md | 11 +--
code/framework/api-pub-sub-jetty/pom.xml | 2 +-
code/framework/api-pub-sub/pom.xml | 2 +-
code/framework/api/pom.xml | 2 +-
.../api/schema/FileSchemaFactory.java | 26 +++++-
.../api/schema/FileSchemaFactoryTest.java | 90 +++++++++++++++++++
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 +-
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.326.md | 18 ++++
pom.xml | 2 +-
resources/pom.xml | 2 +-
scripts/build | 2 +-
scripts/check-pasturestack-source | 9 +-
scripts/check-release-artifact | 2 +-
97 files changed, 245 insertions(+), 108 deletions(-)
create mode 100644 docs/releases/orchestration-engine-0.183.326.md
diff --git a/COMPATIBILITY.md b/COMPATIBILITY.md
index e86319b85e..cea0e9411a 100644
--- a/COMPATIBILITY.md
+++ b/COMPATIBILITY.md
@@ -81,12 +81,13 @@ template configuration retains its explicit `VERSION_2_3_0` compatibility
setting. This dependency update does not change API, database schema, or
template configuration.
-Engine `0.183.325` includes `projectTemplate.isPublic` in non-admin v1 API
-responses as a read-only field. The admin create and update permission remains
-unchanged. Public templates still have no owning `accountId`; their `remove`
-action link is omitted for non-admin callers, while private template owners
-and admins retain it. Direct update and delete authorization remains enforced
-by the existing policy. There is no database migration.
+Engine `0.183.326` restores `projectTemplate.isPublic` in non-admin v1 API
+responses as a read-only field. In `0.183.325`, v2-beta exposed the field but
+the frozen v1 user schema omitted it. The admin create and update permission
+remains unchanged. Public templates still have no owning `accountId`; their
+`remove` action link is omitted for non-admin callers, while private template
+owners and admins retain it. Direct update and delete authorization remains
+enforced by the existing policy. There is no database migration.
The `v0.183.324` tag is source-only and has no published release artifact.
## External identity type upgrades
diff --git a/README.md b/README.md
index 12ab22fcf9..a93b03166a 100644
--- a/README.md
+++ b/README.md
@@ -14,10 +14,11 @@ preserved upstream boundary.
## Current release
The latest public Engine release is
-[`v0.183.325`](https://github.com/PastureStack/orchestration-engine/releases/tag/v0.183.325).
-It exposes `projectTemplate.isPublic` to non-admin readers as a read-only field
-and omits unavailable remove actions on non-owned templates. See the
-[release note](docs/releases/orchestration-engine-0.183.325.md) for behavior,
+[`v0.183.326`](https://github.com/PastureStack/orchestration-engine/releases/tag/v0.183.326).
+It restores read-only `projectTemplate.isPublic` in both v1 and v2-beta
+responses for non-admin readers and omits unavailable remove actions on
+non-owned templates. See the
+[release note](docs/releases/orchestration-engine-0.183.326.md) for behavior,
tests, and compatibility details. Previous release notes remain in
[`docs/releases`](docs/releases), and the
[GitHub release history](https://github.com/PastureStack/orchestration-engine/releases)
@@ -45,7 +46,7 @@ bash scripts/check-cattle-jdk25-full-package
After the gate passes, package and check the release artifact:
```sh
-ENGINE_VERSION=0.183.325 bash scripts/build --release
+ENGINE_VERSION=0.183.326 bash scripts/build --release
bash scripts/check-release-artifact dist/artifacts/cattle.jar
```
diff --git a/code/framework/api-pub-sub-jetty/pom.xml b/code/framework/api-pub-sub-jetty/pom.xml
index 99615d4589..0216a00a54 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.325
+ 0.183.326
../../parent/pom.xml
diff --git a/code/framework/api-pub-sub/pom.xml b/code/framework/api-pub-sub/pom.xml
index e6710dc8ee..5a0df01a68 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.325
+ 0.183.326
../../parent/pom.xml
diff --git a/code/framework/api/pom.xml b/code/framework/api/pom.xml
index 5f144d2cf2..4bf06b4581 100644
--- a/code/framework/api/pom.xml
+++ b/code/framework/api/pom.xml
@@ -4,7 +4,7 @@
cattle-parent
io.cattle
- 0.183.325
+ 0.183.326
../../parent/pom.xml
diff --git a/code/framework/api/src/main/java/io/cattle/platform/api/schema/FileSchemaFactory.java b/code/framework/api/src/main/java/io/cattle/platform/api/schema/FileSchemaFactory.java
index 725ea010e2..6f8a8b5a0b 100644
--- a/code/framework/api/src/main/java/io/cattle/platform/api/schema/FileSchemaFactory.java
+++ b/code/framework/api/src/main/java/io/cattle/platform/api/schema/FileSchemaFactory.java
@@ -89,7 +89,9 @@ protected void init() {
protected void copyAccessors(Schema schema) {
SchemaFactory parentSchemaFactory = schemaFactory;
- mergeProjectMemberExternalIdTypeOptions(schema, parentSchemaFactory.getSchema(schema.getId()));
+ Schema coreSchema = parentSchemaFactory.getSchema(schema.getId());
+ mergeProjectMemberExternalIdTypeOptions(schema, coreSchema);
+ mergeProjectTemplatePublicReadField(schema, coreSchema);
Class> clz = parentSchemaFactory.getSchemaClass(schema.getId());
if (clz == null) {
return;
@@ -129,6 +131,28 @@ protected void mergeProjectMemberExternalIdTypeOptions(Schema schema, Schema par
((FieldImpl) field).setOptions(new ArrayList(options));
}
+ protected void mergeProjectTemplatePublicReadField(Schema schema, Schema parentSchema) {
+ if (parentSchema == null || !"projectTemplate".equals(schema.getId()) ||
+ schema.getResourceFields().containsKey("isPublic")) {
+ return;
+ }
+
+ Field parentField = parentSchema.getResourceFields().get("isPublic");
+ if (!(parentField instanceof FieldImpl)) {
+ return;
+ }
+
+ // v1 loads frozen .ser schemas. The current user auth overlay grants
+ // read access, but cannot add a field missing from those snapshots.
+ // Copy only this public-state field and keep mutation admin-only.
+ FieldImpl readOnly = new FieldImpl(parentField);
+ readOnly.setName("isPublic");
+ readOnly.setCreate(false);
+ readOnly.setUpdate(false);
+ readOnly.setReadOnCreateOnly(false);
+ schema.getResourceFields().put("isPublic", readOnly);
+ }
+
public String getFile() {
return file;
}
diff --git a/code/framework/api/src/test/java/io/cattle/platform/api/schema/FileSchemaFactoryTest.java b/code/framework/api/src/test/java/io/cattle/platform/api/schema/FileSchemaFactoryTest.java
index d47288efc2..ae54e0b76e 100644
--- a/code/framework/api/src/test/java/io/cattle/platform/api/schema/FileSchemaFactoryTest.java
+++ b/code/framework/api/src/test/java/io/cattle/platform/api/schema/FileSchemaFactoryTest.java
@@ -1,7 +1,11 @@
package io.cattle.platform.api.schema;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
import static org.junit.Assert.assertSame;
+import static org.junit.Assert.assertTrue;
import io.github.ibuildthecloud.gdapi.factory.SchemaFactory;
import io.github.ibuildthecloud.gdapi.factory.impl.AbstractSchemaFactory;
@@ -16,6 +20,9 @@
import java.io.InputStream;
import java.io.ObjectOutputStream;
import java.net.URL;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
@@ -95,6 +102,89 @@ public void enrichesFrozenV1ProjectMemberIdentityTypesFromCoreSchema() throws Ex
.getResourceFields().get("externalIdType").getOptions());
}
+ @Test
+ public void exposesFrozenV1ProjectTemplatePublicStateWithoutGrantingWrites() throws Exception {
+ String resourceName = "schemas/v1-project-template-user.bin";
+ SchemaImpl frozen = schema("projectTemplate", "projectTemplates");
+ SchemaImpl core = schema("projectTemplate", "projectTemplates");
+ FieldImpl coreField = new FieldImpl();
+ coreField.setName("isPublic");
+ coreField.setType("boolean");
+ coreField.setCreate(true);
+ coreField.setUpdate(true);
+ core.getResourceFields().put("isPublic", coreField);
+
+ Thread.currentThread().setContextClassLoader(new ResourceClassLoader(resourceName,
+ serialize(Arrays.