Skip to content

Commit efb85f5

Browse files
authored
Add mirror access control (#1085)
Motivation: Sometimes you need to restrict access to specific repositories without allowing mirroring for all repositories. These repositories may contain sensitive information or code that is only available to a select group of members. Modifications: - Add `MirrorAccessController` that can allow or disallow access to the remote repositories for mirroring. - It is used to check if a scheduled mirroring task or a task triggered by UI is allowed to access. - `MirrorListener.onCreate()` and `MirrorListener.onUpdate()` events are newly added. The events could be used as an extension point to detect a new remote URL pattern and integrate external systems such as a workflow or an email notification. - Add CRUD REST API for administrators - GET `/api/v1/mirror/access` to retrieve all mirror access controls. - POST `/api/v1/mirror/access` to create a mirror access controls. - and so on... - In addition to the REST API, a mirror access control can be added with `MirrorAccessController.allow(...)` API which is exposed by `PluginContext.mirrorAccessController()`. - Add `CrudRepository` abstraction to easily create and update a collection of entities in a directory. - This API would be useful especially when we implement UI-based CRUD operations. - Add mirror access control UI for administrators - CRUD operations are supported. Result: - Administrators can restrict access to remote repositories when mirroring. - You can receive notifications when a new mirror is created or an existing mirror is updated through `MirrorListener`.
1 parent 015db56 commit efb85f5

File tree

87 files changed

+3625
-456
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

87 files changed

+3625
-456
lines changed

client/java-armeria-xds/src/test/java/com/linecorp/centraldogma/client/armeria/xds/AuthUpstreamTest.java

+4-9
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,6 @@
2626
import org.junit.jupiter.api.Test;
2727
import org.junit.jupiter.api.extension.RegisterExtension;
2828

29-
import com.fasterxml.jackson.core.JsonProcessingException;
3029
import com.fasterxml.jackson.databind.JsonNode;
3130
import com.google.common.collect.ImmutableList;
3231
import com.google.common.collect.ImmutableMap;
@@ -71,14 +70,10 @@ protected void configure(CentralDogmaBuilder builder) {
7170

7271
@Override
7372
protected void configureClient(ArmeriaCentralDogmaBuilder builder) {
74-
try {
75-
final String accessToken = getAccessToken(
76-
WebClient.of("http://127.0.0.1:" + dogma.serverAddress().getPort()),
77-
TestAuthMessageUtil.USERNAME, TestAuthMessageUtil.PASSWORD);
78-
builder.accessToken(accessToken);
79-
} catch (JsonProcessingException e) {
80-
throw new RuntimeException(e);
81-
}
73+
final String accessToken = getAccessToken(
74+
WebClient.of("http://127.0.0.1:" + dogma.serverAddress().getPort()),
75+
TestAuthMessageUtil.USERNAME, TestAuthMessageUtil.PASSWORD);
76+
builder.accessToken(accessToken);
8277
}
8378

8479
@Override
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
/*
2+
* Copyright 2025 LINE Corporation
3+
*
4+
* LINE Corporation licenses this file to you under the Apache License,
5+
* version 2.0 (the "License"); you may not use this file except in compliance
6+
* with the License. You may obtain a copy of the License at:
7+
*
8+
* https://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12+
* WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13+
* License for the specific language governing permissions and limitations
14+
* under the License.
15+
*/
16+
17+
package com.linecorp.centraldogma.common;
18+
19+
/**
20+
* A {@link MirrorException} raised when failed to access to the remote repository for mirroring.
21+
*/
22+
public final class MirrorAccessException extends MirrorException {
23+
private static final long serialVersionUID = 6673537965128335081L;
24+
25+
/**
26+
* Creates a new instance.
27+
*/
28+
public MirrorAccessException(String message) {
29+
super(message);
30+
}
31+
32+
/**
33+
* Creates a new instance.
34+
*/
35+
public MirrorAccessException(String message, Throwable cause) {
36+
super(message, cause);
37+
}
38+
}

common/src/main/java/com/linecorp/centraldogma/internal/api/v1/MirrorDto.java

+13-140
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,6 @@
1717

1818
package com.linecorp.centraldogma.internal.api.v1;
1919

20-
import static com.google.common.base.MoreObjects.firstNonNull;
21-
import static java.util.Objects.requireNonNull;
22-
2320
import java.util.Objects;
2421

2522
import javax.annotation.Nullable;
@@ -28,28 +25,11 @@
2825
import com.fasterxml.jackson.annotation.JsonInclude;
2926
import com.fasterxml.jackson.annotation.JsonInclude.Include;
3027
import com.fasterxml.jackson.annotation.JsonProperty;
31-
import com.google.common.base.MoreObjects;
3228

3329
@JsonInclude(Include.NON_NULL)
34-
public final class MirrorDto {
30+
public final class MirrorDto extends MirrorRequest {
3531

36-
private final String id;
37-
private final boolean enabled;
38-
private final String projectName;
39-
@Nullable
40-
private final String schedule;
41-
private final String direction;
42-
private final String localRepo;
43-
private final String localPath;
44-
private final String remoteScheme;
45-
private final String remoteUrl;
46-
private final String remotePath;
47-
private final String remoteBranch;
48-
@Nullable
49-
private final String gitignore;
50-
private final String credentialId;
51-
@Nullable
52-
private final String zone;
32+
private final boolean allow;
5333

5434
@JsonCreator
5535
public MirrorDto(@JsonProperty("id") String id,
@@ -65,94 +45,16 @@ public MirrorDto(@JsonProperty("id") String id,
6545
@JsonProperty("remoteBranch") String remoteBranch,
6646
@JsonProperty("gitignore") @Nullable String gitignore,
6747
@JsonProperty("credentialId") String credentialId,
68-
@JsonProperty("zone") @Nullable String zone) {
69-
this.id = requireNonNull(id, "id");
70-
this.enabled = firstNonNull(enabled, true);
71-
this.projectName = requireNonNull(projectName, "projectName");
72-
this.schedule = schedule;
73-
this.direction = requireNonNull(direction, "direction");
74-
this.localRepo = requireNonNull(localRepo, "localRepo");
75-
this.localPath = requireNonNull(localPath, "localPath");
76-
this.remoteScheme = requireNonNull(remoteScheme, "remoteScheme");
77-
this.remoteUrl = requireNonNull(remoteUrl, "remoteUrl");
78-
this.remotePath = requireNonNull(remotePath, "remotePath");
79-
this.remoteBranch = requireNonNull(remoteBranch, "remoteBranch");
80-
this.gitignore = gitignore;
81-
this.credentialId = requireNonNull(credentialId, "credentialId");
82-
this.zone = zone;
83-
}
84-
85-
@JsonProperty("id")
86-
public String id() {
87-
return id;
88-
}
89-
90-
@JsonProperty("enabled")
91-
public boolean enabled() {
92-
return enabled;
93-
}
94-
95-
@JsonProperty("projectName")
96-
public String projectName() {
97-
return projectName;
98-
}
99-
100-
@Nullable
101-
@JsonProperty("schedule")
102-
public String schedule() {
103-
return schedule;
104-
}
105-
106-
@JsonProperty("direction")
107-
public String direction() {
108-
return direction;
109-
}
110-
111-
@JsonProperty("localRepo")
112-
public String localRepo() {
113-
return localRepo;
114-
}
115-
116-
@JsonProperty("localPath")
117-
public String localPath() {
118-
return localPath;
119-
}
120-
121-
@JsonProperty("remoteScheme")
122-
public String remoteScheme() {
123-
return remoteScheme;
124-
}
125-
126-
@JsonProperty("remoteUrl")
127-
public String remoteUrl() {
128-
return remoteUrl;
129-
}
130-
131-
@JsonProperty("remotePath")
132-
public String remotePath() {
133-
return remotePath;
134-
}
135-
136-
@JsonProperty("remoteBranch")
137-
public String remoteBranch() {
138-
return remoteBranch;
139-
}
140-
141-
@Nullable
142-
@JsonProperty("gitignore")
143-
public String gitignore() {
144-
return gitignore;
145-
}
146-
147-
@JsonProperty("credentialId")
148-
public String credentialId() {
149-
return credentialId;
48+
@JsonProperty("zone") @Nullable String zone,
49+
@JsonProperty("allow") boolean allow) {
50+
super(id, enabled, projectName, schedule, direction, localRepo, localPath, remoteScheme, remoteUrl,
51+
remotePath, remoteBranch, gitignore, credentialId, zone);
52+
this.allow = allow;
15053
}
15154

152-
@Nullable
153-
@JsonProperty("zone")
154-
public String zone() {
155-
return zone;
55+
@JsonProperty("allow")
56+
public boolean allow() {
57+
return allow;
15658
}
15759

15860
@Override
@@ -164,45 +66,16 @@ public boolean equals(Object o) {
16466
return false;
16567
}
16668
final MirrorDto mirrorDto = (MirrorDto) o;
167-
return id.equals(mirrorDto.id) &&
168-
enabled == mirrorDto.enabled &&
169-
projectName.equals(mirrorDto.projectName) &&
170-
Objects.equals(schedule, mirrorDto.schedule) &&
171-
direction.equals(mirrorDto.direction) &&
172-
localRepo.equals(mirrorDto.localRepo) &&
173-
localPath.equals(mirrorDto.localPath) &&
174-
remoteScheme.equals(mirrorDto.remoteScheme) &&
175-
remoteUrl.equals(mirrorDto.remoteUrl) &&
176-
remotePath.equals(mirrorDto.remotePath) &&
177-
remoteBranch.equals(mirrorDto.remoteBranch) &&
178-
Objects.equals(gitignore, mirrorDto.gitignore) &&
179-
credentialId.equals(mirrorDto.credentialId) &&
180-
Objects.equals(zone, mirrorDto.zone);
69+
return super.equals(o) && allow == mirrorDto.allow;
18170
}
18271

18372
@Override
18473
public int hashCode() {
185-
return Objects.hash(id, projectName, schedule, direction, localRepo, localPath, remoteScheme,
186-
remoteUrl, remotePath, remoteBranch, gitignore, credentialId, enabled, zone);
74+
return super.hashCode() * 31 + Objects.hash(allow);
18775
}
18876

18977
@Override
19078
public String toString() {
191-
return MoreObjects.toStringHelper(this)
192-
.omitNullValues()
193-
.add("id", id)
194-
.add("enabled", enabled)
195-
.add("projectName", projectName)
196-
.add("schedule", schedule)
197-
.add("direction", direction)
198-
.add("localRepo", localRepo)
199-
.add("localPath", localPath)
200-
.add("remoteScheme", remoteScheme)
201-
.add("remoteUrl", remoteUrl)
202-
.add("remotePath", remotePath)
203-
.add("gitignore", gitignore)
204-
.add("credentialId", credentialId)
205-
.add("zone", zone)
206-
.toString();
79+
return toStringHelper().add("allow", allow).toString();
20780
}
20881
}

0 commit comments

Comments
 (0)