Skip to content

Commit b328123

Browse files
committed
add relative support
1 parent bf48c0b commit b328123

File tree

2 files changed

+66
-10
lines changed

2 files changed

+66
-10
lines changed

libs/entitlement/src/main/java/org/elasticsearch/entitlement/runtime/policy/entitlements/FilesEntitlement.java

Lines changed: 61 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,33 @@ public enum BaseDir {
4141

4242
public sealed interface FileData {
4343

44+
sealed interface RelativeFileData extends FileData {
45+
BaseDir baseDir();
46+
47+
Stream<Path> resolveRelativePaths(PathLookup pathLookup);
48+
49+
@Override
50+
default Stream<Path> resolvePaths(PathLookup pathLookup) {
51+
Objects.requireNonNull(pathLookup);
52+
var relativePaths = resolveRelativePaths(pathLookup);
53+
switch (baseDir()) {
54+
case CONFIG:
55+
return relativePaths.map(relativePath -> pathLookup.configDir().resolve(relativePath));
56+
case DATA:
57+
// multiple data dirs are a pain...we need the combination of relative paths and data dirs
58+
List<Path> paths = new ArrayList<>();
59+
for (var relativePath : relativePaths.toList()) {
60+
for (var dataDir : pathLookup.dataDirs()) {
61+
paths.add(dataDir.resolve(relativePath));
62+
}
63+
}
64+
return paths.stream();
65+
default:
66+
throw new IllegalArgumentException();
67+
}
68+
}
69+
}
70+
4471
final class AbsolutePathFileData implements FileData {
4572
private final Path path;
4673
private final Mode mode;
@@ -122,14 +149,25 @@ public int hashCode() {
122149
record PathSettingFileData(String setting, Mode mode) implements FileData {
123150
@Override
124151
public Stream<Path> resolvePaths(PathLookup pathLookup) {
125-
if (setting.contains("*")) {
126-
return pathLookup.settingGlobResolver().apply(setting).map(Path::of);
127-
}
128-
String path = pathLookup.settingResolver().apply(setting);
129-
return path == null ? Stream.of() : Stream.of(Path.of(path));
152+
return FileData.resolvePathSettings(pathLookup, setting);
130153
}
131154
}
132155

156+
record RelativePathSettingFileData(String setting, BaseDir baseDir, Mode mode) implements FileData, RelativeFileData {
157+
@Override
158+
public Stream<Path> resolveRelativePaths(PathLookup pathLookup) {
159+
return FileData.resolvePathSettings(pathLookup, setting);
160+
}
161+
}
162+
163+
private static Stream<Path> resolvePathSettings(PathLookup pathLookup, String setting) {
164+
if (setting.contains("*")) {
165+
return pathLookup.settingGlobResolver().apply(setting).map(Path::of);
166+
}
167+
String path = pathLookup.settingResolver().apply(setting);
168+
return path == null ? Stream.of() : Stream.of(Path.of(path));
169+
}
170+
133171
static FileData ofPath(Path path, Mode mode) {
134172
assert path.isAbsolute();
135173
return new AbsolutePathFileData(path, mode);
@@ -144,6 +182,10 @@ static FileData ofPathSetting(String setting, Mode mode) {
144182
return new PathSettingFileData(setting, mode);
145183
}
146184

185+
static FileData ofRelativePathSetting(String setting, BaseDir baseDir, Mode mode) {
186+
return new RelativePathSettingFileData(setting, baseDir, mode);
187+
}
188+
147189
Stream<Path> resolvePaths(PathLookup pathLookup);
148190

149191
Mode mode();
@@ -181,15 +223,16 @@ public static FilesEntitlement build(List<Object> paths) {
181223
String relativePathAsString = file.remove("relative_path");
182224
String relativeTo = file.remove("relative_to");
183225
String pathSetting = file.remove("path_setting");
226+
String relativePathSetting = file.remove("relative_path_setting");
184227
String modeAsString = file.remove("mode");
185228

186229
if (file.isEmpty() == false) {
187230
throw new PolicyValidationException("unknown key(s) [" + file + "] in a listed file for files entitlement");
188231
}
189-
int foundKeys = (pathAsString != null ? 1 : 0) + (relativePathAsString != null ? 1 : 0) + (pathSetting != null ? 1 : 0);
232+
int foundKeys = (pathAsString != null ? 1 : 0) + (relativePathAsString != null ? 1 : 0) + (pathSetting != null ? 1 : 0) + (relativePathSetting != null ? 1 : 0) + (modeAsString != null ? 1 : 0);
190233
if (foundKeys != 1) {
191234
throw new PolicyValidationException(
192-
"files entitlement must contain one of [path, relative_path, path_setting] for every entry"
235+
"files entitlement must contain one of [path, relative_path, path_setting, relative_path_setting] for every entry"
193236
);
194237
}
195238

@@ -198,11 +241,15 @@ public static FilesEntitlement build(List<Object> paths) {
198241
}
199242
Mode mode = parseMode(modeAsString);
200243

244+
BaseDir baseDir = null;
245+
if (relativeTo != null) {
246+
baseDir = parseBaseDir(relativeTo);
247+
}
248+
201249
if (relativePathAsString != null) {
202-
if (relativeTo == null) {
250+
if (baseDir == null) {
203251
throw new PolicyValidationException("files entitlement with a 'relative_path' must specify 'relative_to'");
204252
}
205-
final BaseDir baseDir = parseBaseDir(relativeTo);
206253

207254
Path relativePath = Path.of(relativePathAsString);
208255
if (relativePath.isAbsolute()) {
@@ -217,6 +264,11 @@ public static FilesEntitlement build(List<Object> paths) {
217264
filesData.add(FileData.ofPath(path, mode));
218265
} else if (pathSetting != null) {
219266
filesData.add(FileData.ofPathSetting(pathSetting, mode));
267+
} else if (relativePathSetting != null) {
268+
if (baseDir == null) {
269+
throw new PolicyValidationException("files entitlement with a 'relative_path_setting' must specify 'relative_to'");
270+
}
271+
filesData.add(FileData.ofRelativePathSetting(relativePathSetting, baseDir, mode));
220272
} else {
221273
throw new AssertionError("File entry validation error");
222274
}

libs/entitlement/src/test/java/org/elasticsearch/entitlement/runtime/policy/PolicyParserTests.java

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,9 @@ public void testParseFiles() throws IOException {
166166
mode: "read_write"
167167
- path_setting: foo.bar
168168
mode: read
169+
- relative_path_setting: foo.bar
170+
relative_to: config
171+
mode: read
169172
""".getBytes(StandardCharsets.UTF_8)), "test-policy.yaml", false).parsePolicy();
170173
expected = new Policy(
171174
"test-policy.yaml",
@@ -178,7 +181,8 @@ public void testParseFiles() throws IOException {
178181
Map.of("relative_path", "test/path/to/file", "mode", "read_write", "relative_to", "data"),
179182
Map.of("relative_path", "test/path/to/read-dir/", "mode", "read", "relative_to", "config"),
180183
Map.of("path", "/path/to/file", "mode", "read_write"),
181-
Map.of("path_setting", "foo.bar", "mode", "read")
184+
Map.of("path_setting", "foo.bar", "mode", "read"),
185+
Map.of("relative_path_setting", "foo.bar", "relative_to", "config", "mode", "read")
182186
)
183187
)
184188
)

0 commit comments

Comments
 (0)