Skip to content

Commit 7bac7be

Browse files
thjaeckleclaude
andcommitted
Make subjects and resources optional on policy entries
With entry-level references, an entry can inherit subjects and resources from referenced entries, making explicit declaration unnecessary. Both fields now default to empty when absent from JSON. This enables patterns like: - Entry with only references (inherits everything) - Entry with only subjects (shared-subjects for local references) Updated ImmutablePolicyEntry.fromJson, OpenAPI schema, and JSON schema. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
1 parent 83328c5 commit 7bac7be

5 files changed

Lines changed: 31 additions & 39 deletions

File tree

documentation/src/main/resources/jsonschema/policy.json

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -202,11 +202,7 @@
202202
},
203203
"example": ["subjects"]
204204
}
205-
},
206-
"required": [
207-
"subjects",
208-
"resources"
209-
]
205+
}
210206
}
211207
}
212208
},

documentation/src/main/resources/openapi/ditto-api-2.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10730,7 +10730,10 @@ components:
1073010730
$ref: '#/components/schemas/PolicyEntry'
1073110731
PolicyEntry:
1073210732
type: object
10733-
description: Single policy entry containing Subjects and Resources.
10733+
description: |-
10734+
Single policy entry. Both `subjects` and `resources` are optional — they
10735+
default to empty when absent. An entry may define `references` to inherit
10736+
subjects, resources, and namespaces from other entries (local or imported).
1073410737
properties:
1073510738
subjects:
1073610739
$ref: '#/components/schemas/Subjects'
@@ -10754,9 +10757,6 @@ components:
1075410757
$ref: '#/components/schemas/AllowedImportAdditions'
1075510758
references:
1075610759
$ref: '#/components/schemas/References'
10757-
required:
10758-
- subjects
10759-
- resources
1076010760
Subjects:
1076110761
type: object
1076210762
description: A SubjectEntry defines who is addressed.

documentation/src/main/resources/openapi/sources/schemas/policies/policyEntry.yml

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,10 @@
99
#
1010
# SPDX-License-Identifier: EPL-2.0
1111
type: object
12-
description: Single policy entry containing Subjects and Resources.
12+
description: |-
13+
Single policy entry. Both `subjects` and `resources` are optional — they
14+
default to empty when absent. An entry may define `references` to inherit
15+
subjects, resources, and namespaces from other entries (local or imported).
1316
properties:
1417
subjects:
1518
$ref: 'subjects.yml'
@@ -23,6 +26,3 @@ properties:
2326
$ref: 'allowedImportAdditions.yml'
2427
references:
2528
$ref: 'references.yml'
26-
required:
27-
- subjects
28-
- resources

policies/model/src/main/java/org/eclipse/ditto/policies/model/ImmutablePolicyEntry.java

Lines changed: 13 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -28,12 +28,10 @@
2828
import javax.annotation.Nullable;
2929
import javax.annotation.concurrent.Immutable;
3030

31-
import org.eclipse.ditto.base.model.exceptions.DittoJsonException;
3231
import org.eclipse.ditto.base.model.json.JsonSchemaVersion;
3332
import org.eclipse.ditto.json.JsonArrayBuilder;
3433
import org.eclipse.ditto.json.JsonFactory;
3534
import org.eclipse.ditto.json.JsonField;
36-
import org.eclipse.ditto.json.JsonMissingFieldException;
3735
import org.eclipse.ditto.json.JsonObject;
3836
import org.eclipse.ditto.json.JsonPointer;
3937
import org.eclipse.ditto.json.JsonValue;
@@ -197,30 +195,24 @@ public static PolicyEntry of(final Label label, final Subjects subjects, final R
197195
* @return a new Policy entry which is initialised with the extracted data from {@code jsonObject}.
198196
* @throws NullPointerException if {@code label} or {@code jsonObject} is {@code null}.
199197
* @throws IllegalArgumentException if {@code label} is empty.
200-
* @throws DittoJsonException if {@code jsonObject}
201-
* <ul>
202-
* <li>is empty or</li>
203-
* <li>contains only a field with the schema version.</li>
204-
* </ul>
198+
* @throws NullPointerException if {@code jsonObject} is {@code null}.
205199
*/
206200
public static PolicyEntry fromJson(final CharSequence label, final JsonObject jsonObject) {
207201
checkNotNull(jsonObject, "JSON object");
208202
final Label lbl = Label.of(label);
209203

210-
try {
211-
final JsonObject subjectsJsonObject = jsonObject.getValueOrThrow(JsonFields.SUBJECTS);
212-
final Subjects subjectsFromJson = PoliciesModelFactory.newSubjects(subjectsJsonObject);
213-
final JsonObject resourcesJsonObject = jsonObject.getValueOrThrow(JsonFields.RESOURCES);
214-
final Resources resourcesFromJson = PoliciesModelFactory.newResources(resourcesJsonObject);
215-
final List<String> namespacesFromJson = readNamespaces(jsonObject);
216-
final ImportableType importType = readImportableType(jsonObject).orElse(ImportableType.IMPLICIT);
217-
final Set<AllowedImportAddition> additions = readAllowedImportAdditions(jsonObject);
218-
final List<EntryReference> referencesFromJson = readReferences(jsonObject);
219-
return new ImmutablePolicyEntry(lbl, subjectsFromJson, resourcesFromJson, namespacesFromJson,
220-
importType, additions, referencesFromJson);
221-
} catch (final JsonMissingFieldException e) {
222-
throw new DittoJsonException(e);
223-
}
204+
final Subjects subjectsFromJson = jsonObject.getValue(JsonFields.SUBJECTS)
205+
.map(PoliciesModelFactory::newSubjects)
206+
.orElseGet(PoliciesModelFactory::emptySubjects);
207+
final Resources resourcesFromJson = jsonObject.getValue(JsonFields.RESOURCES)
208+
.map(PoliciesModelFactory::newResources)
209+
.orElseGet(PoliciesModelFactory::emptyResources);
210+
final List<String> namespacesFromJson = readNamespaces(jsonObject);
211+
final ImportableType importType = readImportableType(jsonObject).orElse(ImportableType.IMPLICIT);
212+
final Set<AllowedImportAddition> additions = readAllowedImportAdditions(jsonObject);
213+
final List<EntryReference> referencesFromJson = readReferences(jsonObject);
214+
return new ImmutablePolicyEntry(lbl, subjectsFromJson, resourcesFromJson, namespacesFromJson,
215+
importType, additions, referencesFromJson);
224216
}
225217

226218
private static Optional<ImportableType> readImportableType(final JsonObject json) {

policies/model/src/test/java/org/eclipse/ditto/policies/model/ImmutablePolicyEntryTest.java

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@
2121
import java.util.NoSuchElementException;
2222
import java.util.Set;
2323

24-
import org.eclipse.ditto.base.model.exceptions.DittoJsonException;
24+
2525
import org.eclipse.ditto.base.model.json.JsonSchemaVersion;
2626
import org.eclipse.ditto.json.JsonArray;
2727
import org.eclipse.ditto.json.JsonFactory;
@@ -64,11 +64,13 @@ public void testFromJsonWithNullLabel() {
6464
ImmutablePolicyEntry.fromJson(null, JsonFactory.newObjectBuilder().build());
6565
}
6666

67-
@Test(expected = DittoJsonException.class)
67+
@Test
6868
public void testFromJsonEmptyWithLabel() {
6969
final JsonObject jsonObject = JsonFactory.newObjectBuilder().build();
7070

71-
ImmutablePolicyEntry.fromJson(LABEL_END_USER, jsonObject);
71+
final PolicyEntry entry = ImmutablePolicyEntry.fromJson(LABEL_END_USER, jsonObject);
72+
assertThat(entry.getSubjects()).isEmpty();
73+
assertThat(entry.getResources()).isEmpty();
7274
}
7375

7476
@Test(expected = PolicyEntryInvalidException.class)
@@ -84,13 +86,15 @@ public void testFromJsonWithoutImportableType() {
8486
assertThat(entry.getImportableType()).isEqualTo(ImportableType.IMPLICIT);
8587
}
8688

87-
@Test(expected = DittoJsonException.class)
89+
@Test
8890
public void testFromJsonOnlySchemaVersion() {
8991
final JsonObject jsonObject = JsonFactory.newObjectBuilder()
9092
.set(JsonSchemaVersion.getJsonKey(), JsonSchemaVersion.V_2.toInt())
9193
.build();
9294

93-
ImmutablePolicyEntry.fromJson("EndUser", jsonObject);
95+
final PolicyEntry entry = ImmutablePolicyEntry.fromJson("EndUser", jsonObject);
96+
assertThat(entry.getSubjects()).isEmpty();
97+
assertThat(entry.getResources()).isEmpty();
9498
}
9599

96100
@Test

0 commit comments

Comments
 (0)