Skip to content

Commit fa70211

Browse files
authored
Merge branch 'master' into fix/humanize-timestamp
2 parents 0da8e49 + cc3782e commit fa70211

File tree

742 files changed

+29427
-6396
lines changed

Some content is hidden

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

742 files changed

+29427
-6396
lines changed

.github/.codecov.yml

+9-14
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,19 @@
11
comment:
2-
layout: "header, files, footer" # remove "new" from "header" and "footer"
3-
hide_project_coverage: true # set to false
2+
layout: "condensed_header, condensed_files, condensed_footer"
3+
hide_project_coverage: true
44
require_changes: false # if true: only post the comment if coverage changes
55

66
codecov:
77
#due to ci-optimization, reports for modules that have not changed may be quite old
88
max_report_age: off
99

10+
github_checks:
11+
#Hide annotations that show up in github PR reviews. There still is a red bar next to lines not covered
12+
annotations: false
13+
1014
flag_management:
1115
default_rules: # the rules that will be followed for any flag added, generally
1216
carryforward: true
13-
statuses:
14-
- type: project
15-
target: auto
16-
threshold: 0% #Not enforcing project coverage yet.
17-
- type: patch
18-
target: 90%
1917
individual_flags: # exceptions to the default rules above, stated flag by flag
2018
- name: frontend
2119
paths:
@@ -55,11 +53,8 @@ flag_management:
5553
- "metadata-ingestion-modules/prefect-plugin/**"
5654
coverage:
5755
status:
58-
project:
59-
default:
60-
target: 0% # no threshold enforcement yet
61-
only_pulls: true
56+
project: false
6257
patch:
6358
default:
64-
target: 90% # for new code added in the patch
65-
only_pulls: true
59+
target: 75% # for new code added in the patch
60+
only_pulls: true

README.md

+28-18
Original file line numberDiff line numberDiff line change
@@ -18,27 +18,38 @@ export const Logo = (props) => {
1818
<!--
1919
HOSTED_DOCS_ONLY-->
2020
<p align="center">
21+
<a href="https://datahubproject.io">
2122
<img alt="DataHub" src="https://raw.githubusercontent.com/datahub-project/static-assets/main/imgs/datahub-logo-color-mark.svg" height="150" />
23+
</a>
2224
</p>
2325
<!-- -->
2426

2527
# DataHub: The Data Discovery Platform for the Modern Data Stack
26-
## Built with ❤️ by <img src="https://datahubproject.io/img/acryl-logo-light-mark.png" width="25"/> [Acryl Data](https://acryldata.io) and <img src="https://datahubproject.io/img/LI-In-Bug.png" width="25"/> [LinkedIn](https://engineering.linkedin.com)
27-
[![Version](https://img.shields.io/github/v/release/datahub-project/datahub?include_prereleases)](https://github.com/datahub-project/datahub/releases/latest)
28-
[![PyPI version](https://badge.fury.io/py/acryl-datahub.svg)](https://badge.fury.io/py/acryl-datahub)
29-
[![build & test](https://github.com/datahub-project/datahub/workflows/build%20&%20test/badge.svg?branch=master&event=push)](https://github.com/datahub-project/datahub/actions?query=workflow%3A%22build+%26+test%22+branch%3Amaster+event%3Apush)
30-
[![Docker Pulls](https://img.shields.io/docker/pulls/acryldata/datahub-gms.svg)](https://hub.docker.com/r/acryldata/datahub-gms)
31-
[![Slack](https://img.shields.io/badge/slack-join_chat-white.svg?logo=slack&style=social)](https://datahubproject.io/slack?utm_source=github&utm_medium=readme&utm_campaign=github_readme)
32-
[![PRs Welcome](https://img.shields.io/badge/PRs-welcome-brightgreen.svg)](https://github.com/datahub-project/datahub/blob/master/docs/CONTRIBUTING.md)
33-
[![GitHub commit activity](https://img.shields.io/github/commit-activity/m/datahub-project/datahub)](https://github.com/datahub-project/datahub/pulls?q=is%3Apr)
34-
[![License](https://img.shields.io/github/license/datahub-project/datahub)](https://github.com/datahub-project/datahub/blob/master/LICENSE)
35-
[![YouTube](https://img.shields.io/youtube/channel/subscribers/UC3qFQC5IiwR5fvWEqi_tJ5w?style=social)](https://www.youtube.com/channel/UC3qFQC5IiwR5fvWEqi_tJ5w)
36-
[![Medium](https://img.shields.io/badge/Medium-12100E?style=for-the-badge&logo=medium&logoColor=white)](https://medium.com/datahub-project)
37-
[![Follow](https://img.shields.io/twitter/follow/datahubproject?label=Follow&style=social)](https://twitter.com/datahubproject)
38-
### 🏠 Hosted DataHub Docs (Courtesy of Acryl Data): [datahubproject.io](https://datahubproject.io/docs)
28+
29+
### Built with ❤️ by <img src="https://datahubproject.io/img/acryl-logo-light-mark.png" width="20"/> [Acryl Data](https://acryldata.io) and <img src="https://datahubproject.io/img/LI-In-Bug.png" width="20"/> [LinkedIn](https://engineering.linkedin.com)
30+
31+
<div>
32+
<a target="_blank" href="https://github.com/datahub-project/datahub/blob/master/LICENSE">
33+
<img alt="Apache 2.0 License" src="https://img.shields.io/badge/License-Apache_2.0-blue.svg?label=license&labelColor=133554&color=1890ff" /></a>
34+
<a target="_blank" href="https://pypi.org/project/acryl-datahub/">
35+
<img alt="PyPI" src="https://img.shields.io/pypi/dm/acryl-datahub?label=downloads&labelColor=133554&color=1890ff" /></a>
36+
<a target="_blank" href="https://github.com/datahub-project/datahub/pulse">
37+
<img alt="GitHub commit activity" src="https://img.shields.io/github/commit-activity/m/datahub-project/datahub?label=commits&labelColor=133554&color=1890ff" /></a>
38+
<br />
39+
<a target="_blank" href="https://pages.acryl.io/slack?utm_source=github&utm_medium=readme&utm_campaign=github_readme">
40+
<img alt="Slack" src="https://img.shields.io/badge/slack-join_community-red.svg?logo=slack&labelColor=133554&color=1890ff" /></a>
41+
<a href="https://www.youtube.com/channel/UC3qFQC5IiwR5fvWEqi_tJ5w">
42+
<img alt="YouTube" src="https://img.shields.io/youtube/channel/subscribers/UC3qFQC5IiwR5fvWEqi_tJ5w?style=flat&logo=youtube&label=subscribers&labelColor=133554&color=1890ff"/></a>
43+
<a href="https://blog.datahubproject.io/">
44+
<img alt="Medium" src="https://img.shields.io/badge/blog-DataHub-red.svg?style=flat&logo=medium&logoColor=white&labelColor=133554&color=1890ff" /></a>
45+
<a href="https://x.com/datahubproject">
46+
<img alt="X (formerly Twitter) Follow" src="https://img.shields.io/badge/follow-datahubproject-red.svg?style=flat&logo=x&labelColor=133554&color=1890ff" /></a>
47+
</div>
3948

4049
---
4150

51+
### 🏠 Docs: [datahubproject.io](https://datahubproject.io/docs)
52+
4253
[Quickstart](https://datahubproject.io/docs/quickstart) |
4354
[Features](https://datahubproject.io/docs/) |
4455
[Roadmap](https://feature-requests.datahubproject.io/roadmap) |
@@ -47,6 +58,7 @@ HOSTED_DOCS_ONLY-->
4758
[Town Hall](https://datahubproject.io/docs/townhalls)
4859

4960
---
61+
5062
> 📣 DataHub Town Hall is the 4th Thursday at 9am US PT of every month - [add it to your calendar!](https://rsvp.datahubproject.io/)
5163
>
5264
> - Town-hall Zoom link: [zoom.datahubproject.io](https://zoom.datahubproject.io)
@@ -70,11 +82,11 @@ Check out DataHub's [Features](docs/features.md) & [Roadmap](https://feature-req
7082

7183
## Demo and Screenshots
7284

73-
There's a [hosted demo environment](https://demo.datahubproject.io/) courtesy of [Acryl Data](https://acryldata.io) where you can explore DataHub without installing it locally
85+
There's a [hosted demo environment](https://demo.datahubproject.io/) courtesy of [Acryl Data](https://acryldata.io) where you can explore DataHub without installing it locally.
7486

7587
## Quickstart
7688

77-
Please follow the [DataHub Quickstart Guide](https://datahubproject.io/docs/quickstart) to get a copy of DataHub up & running locally using [Docker](https://docker.com). As the guide assumes some basic knowledge of Docker, we'd recommend you to go through the "Hello World" example of [A Docker Tutorial for Beginners](https://docker-curriculum.com) if Docker is completely foreign to you.
89+
Please follow the [DataHub Quickstart Guide](https://datahubproject.io/docs/quickstart) to run DataHub locally using [Docker](https://docker.com).
7890

7991
## Development
8092

@@ -106,7 +118,7 @@ We welcome contributions from the community. Please refer to our [Contributing G
106118

107119
## Community
108120

109-
Join our [Slack workspace](https://datahubproject.io/slack?utm_source=github&utm_medium=readme&utm_campaign=github_readme) for discussions and important announcements. You can also find out more about our upcoming [town hall meetings](docs/townhalls.md) and view past recordings.
121+
Join our [Slack workspace](https://pages.acryl.io/slack?utm_source=github&utm_medium=readme&utm_campaign=github_readme) for discussions and important announcements. You can also find out more about our upcoming [town hall meetings](docs/townhalls.md) and view past recordings.
110122

111123
## Security
112124

@@ -159,8 +171,6 @@ Here are the companies that have officially adopted DataHub. Please feel free to
159171
- [Wolt](https://wolt.com)
160172
- [Zynga](https://www.zynga.com)
161173

162-
163-
164174
## Select Articles & Talks
165175

166176
- [DataHub Blog](https://blog.datahubproject.io/)
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package auth;
2+
3+
public class GuestAuthenticationConfigs {
4+
public static final String GUEST_ENABLED_CONFIG_PATH = "auth.guest.enabled";
5+
public static final String GUEST_USER_CONFIG_PATH = "auth.guest.user";
6+
public static final String GUEST_PATH_CONFIG_PATH = "auth.guest.path";
7+
public static final String DEFAULT_GUEST_USER_NAME = "guest";
8+
public static final String DEFAULT_GUEST_PATH = "/public";
9+
10+
private Boolean isEnabled = false;
11+
private String guestUser =
12+
DEFAULT_GUEST_USER_NAME; // Default if not defined but guest auth is enabled.
13+
private String guestPath =
14+
DEFAULT_GUEST_PATH; // The path for initial access to login as guest and bypass login page.
15+
16+
public GuestAuthenticationConfigs(final com.typesafe.config.Config configs) {
17+
if (configs.hasPath(GUEST_ENABLED_CONFIG_PATH)
18+
&& configs.getBoolean(GUEST_ENABLED_CONFIG_PATH)) {
19+
isEnabled = true;
20+
}
21+
if (configs.hasPath(GUEST_USER_CONFIG_PATH)) {
22+
guestUser = configs.getString(GUEST_USER_CONFIG_PATH);
23+
}
24+
if (configs.hasPath(GUEST_PATH_CONFIG_PATH)) {
25+
guestPath = configs.getString(GUEST_PATH_CONFIG_PATH);
26+
}
27+
}
28+
29+
public boolean isGuestEnabled() {
30+
return isEnabled;
31+
}
32+
33+
public String getGuestUser() {
34+
return guestUser;
35+
}
36+
37+
public String getGuestPath() {
38+
return guestPath;
39+
}
40+
}

datahub-frontend/app/controllers/AuthenticationController.java

+21
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66

77
import auth.AuthUtils;
88
import auth.CookieConfigs;
9+
import auth.GuestAuthenticationConfigs;
910
import auth.JAASConfigs;
1011
import auth.NativeAuthenticationConfigs;
1112
import auth.sso.SsoManager;
@@ -58,6 +59,8 @@ public class AuthenticationController extends Controller {
5859
private final CookieConfigs cookieConfigs;
5960
private final JAASConfigs jaasConfigs;
6061
private final NativeAuthenticationConfigs nativeAuthenticationConfigs;
62+
private final GuestAuthenticationConfigs guestAuthenticationConfigs;
63+
6164
private final boolean verbose;
6265

6366
@Inject private org.pac4j.core.config.Config ssoConfig;
@@ -73,6 +76,7 @@ public AuthenticationController(@Nonnull Config configs) {
7376
cookieConfigs = new CookieConfigs(configs);
7477
jaasConfigs = new JAASConfigs(configs);
7578
nativeAuthenticationConfigs = new NativeAuthenticationConfigs(configs);
79+
guestAuthenticationConfigs = new GuestAuthenticationConfigs(configs);
7680
verbose = configs.hasPath(AUTH_VERBOSE_LOGGING) && configs.getBoolean(AUTH_VERBOSE_LOGGING);
7781
}
7882

@@ -110,6 +114,23 @@ public Result authenticate(Http.Request request) {
110114
return Results.redirect(redirectPath);
111115
}
112116

117+
if (guestAuthenticationConfigs.isGuestEnabled()
118+
&& guestAuthenticationConfigs.getGuestPath().equals(redirectPath)) {
119+
final String accessToken =
120+
authClient.generateSessionTokenForUser(guestAuthenticationConfigs.getGuestUser());
121+
redirectPath =
122+
"/"; // We requested guest login by accessing {guestPath} URL. It is not really a target.
123+
CorpuserUrn guestUserUrn = new CorpuserUrn(guestAuthenticationConfigs.getGuestUser());
124+
return Results.redirect(redirectPath)
125+
.withSession(createSessionMap(guestUserUrn.toString(), accessToken))
126+
.withCookies(
127+
createActorCookie(
128+
guestUserUrn.toString(),
129+
cookieConfigs.getTtlInHours(),
130+
cookieConfigs.getAuthCookieSameSite(),
131+
cookieConfigs.getAuthCookieSecure()));
132+
}
133+
113134
// 1. If SSO is enabled, redirect to IdP if not authenticated.
114135
if (ssoManager.isSsoEnabled()) {
115136
return redirectToIdentityProvider(request, redirectPath)

datahub-frontend/conf/application.conf

+5
Original file line numberDiff line numberDiff line change
@@ -203,6 +203,11 @@ auth.oidc.grantType = ${?AUTH_OIDC_GRANT_TYPE}
203203
#
204204
auth.jaas.enabled = ${?AUTH_JAAS_ENABLED}
205205
auth.native.enabled = ${?AUTH_NATIVE_ENABLED}
206+
auth.guest.enabled = ${?GUEST_AUTHENTICATION_ENABLED}
207+
# The name of the guest user id
208+
auth.guest.user = ${?GUEST_AUTHENTICATION_USER}
209+
# The path to bypass login page and get logged in as guest
210+
auth.guest.path = ${?GUEST_AUTHENTICATION_PATH}
206211

207212
# Enforces the usage of a valid email for user sign up
208213
auth.native.signUp.enforceValidEmail = true
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
package security;
2+
3+
import static org.junit.jupiter.api.Assertions.*;
4+
5+
import auth.GuestAuthenticationConfigs;
6+
import com.typesafe.config.Config;
7+
import com.typesafe.config.ConfigFactory;
8+
import org.junit.jupiter.api.BeforeEach;
9+
import org.junit.jupiter.api.Test;
10+
import org.junit.jupiter.api.TestInstance;
11+
import org.junitpioneer.jupiter.ClearEnvironmentVariable;
12+
import org.junitpioneer.jupiter.SetEnvironmentVariable;
13+
14+
@TestInstance(TestInstance.Lifecycle.PER_METHOD)
15+
@SetEnvironmentVariable(key = "DATAHUB_SECRET", value = "test")
16+
@SetEnvironmentVariable(key = "KAFKA_BOOTSTRAP_SERVER", value = "")
17+
@SetEnvironmentVariable(key = "DATAHUB_ANALYTICS_ENABLED", value = "false")
18+
@SetEnvironmentVariable(key = "AUTH_OIDC_ENABLED", value = "true")
19+
@SetEnvironmentVariable(key = "AUTH_OIDC_JIT_PROVISIONING_ENABLED", value = "false")
20+
@SetEnvironmentVariable(key = "AUTH_OIDC_CLIENT_ID", value = "testclient")
21+
@SetEnvironmentVariable(key = "AUTH_OIDC_CLIENT_SECRET", value = "testsecret")
22+
@SetEnvironmentVariable(key = "AUTH_VERBOSE_LOGGING", value = "true")
23+
class GuestAuthenticationConfigsTest {
24+
25+
@BeforeEach
26+
@ClearEnvironmentVariable(key = "GUEST_AUTHENTICATION_ENABLED")
27+
@ClearEnvironmentVariable(key = "GUEST_AUTHENTICATION_USER")
28+
@ClearEnvironmentVariable(key = "GUEST_AUTHENTICATION_PATH")
29+
public void clearConfigCache() {
30+
ConfigFactory.invalidateCaches();
31+
}
32+
33+
@Test
34+
public void testGuestConfigDisabled() {
35+
Config config = ConfigFactory.load();
36+
GuestAuthenticationConfigs guestAuthConfig = new GuestAuthenticationConfigs(config);
37+
assertFalse(guestAuthConfig.isGuestEnabled());
38+
}
39+
40+
@Test
41+
@SetEnvironmentVariable(key = "GUEST_AUTHENTICATION_ENABLED", value = "true")
42+
public void testGuestConfigEnabled() {
43+
Config config = ConfigFactory.load();
44+
GuestAuthenticationConfigs guestAuthConfig = new GuestAuthenticationConfigs(config);
45+
assertTrue(guestAuthConfig.isGuestEnabled());
46+
assertEquals("guest", guestAuthConfig.getGuestUser());
47+
assertEquals("/public", guestAuthConfig.getGuestPath());
48+
}
49+
50+
@Test
51+
@SetEnvironmentVariable(key = "GUEST_AUTHENTICATION_ENABLED", value = "true")
52+
@SetEnvironmentVariable(key = "GUEST_AUTHENTICATION_USER", value = "publicUser")
53+
@SetEnvironmentVariable(key = "GUEST_AUTHENTICATION_PATH", value = "/publicPath")
54+
public void testGuestConfigWithUserEnabled() {
55+
Config config = ConfigFactory.load();
56+
GuestAuthenticationConfigs guestAuthConfig = new GuestAuthenticationConfigs(config);
57+
assertTrue(guestAuthConfig.isGuestEnabled());
58+
assertEquals("publicUser", guestAuthConfig.getGuestUser());
59+
assertEquals("/publicPath", guestAuthConfig.getGuestPath());
60+
}
61+
}

datahub-graphql-core/build.gradle

+1
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ dependencies {
2929

3030
testImplementation externalDependency.mockito
3131
testImplementation externalDependency.testng
32+
testImplementation externalDependency.mockitoInline
3233
}
3334

3435
graphqlCodegen {

datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/GmsGraphQLEngine.java

+6-1
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,7 @@
204204
import com.linkedin.datahub.graphql.resolvers.health.EntityHealthResolver;
205205
import com.linkedin.datahub.graphql.resolvers.incident.EntityIncidentsResolver;
206206
import com.linkedin.datahub.graphql.resolvers.incident.RaiseIncidentResolver;
207+
import com.linkedin.datahub.graphql.resolvers.incident.UpdateIncidentResolver;
207208
import com.linkedin.datahub.graphql.resolvers.incident.UpdateIncidentStatusResolver;
208209
import com.linkedin.datahub.graphql.resolvers.ingest.execution.CancelIngestionExecutionRequestResolver;
209210
import com.linkedin.datahub.graphql.resolvers.ingest.execution.CreateIngestionExecutionRequestResolver;
@@ -1025,7 +1026,8 @@ private void configureQueryResolvers(final RuntimeWiring.Builder builder) {
10251026
new ScrollAcrossEntitiesResolver(this.entityClient, this.viewService))
10261027
.dataFetcher(
10271028
"searchAcrossLineage",
1028-
new SearchAcrossLineageResolver(this.entityClient, this.entityRegistry))
1029+
new SearchAcrossLineageResolver(
1030+
this.entityClient, this.entityRegistry, this.viewService))
10291031
.dataFetcher(
10301032
"scrollAcrossLineage", new ScrollAcrossLineageResolver(this.entityClient))
10311033
.dataFetcher(
@@ -1397,6 +1399,9 @@ private void configureMutationResolvers(final RuntimeWiring.Builder builder) {
13971399
.dataFetcher(
13981400
"updateIncidentStatus",
13991401
new UpdateIncidentStatusResolver(this.entityClient, this.entityService))
1402+
.dataFetcher(
1403+
"updateIncident",
1404+
new UpdateIncidentResolver(this.entityClient, this.entityService))
14001405
.dataFetcher(
14011406
"createForm", new CreateFormResolver(this.entityClient, this.formService))
14021407
.dataFetcher("deleteForm", new DeleteFormResolver(this.entityClient))

datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/analytics/resolver/GetChartsResolver.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -186,7 +186,7 @@ private Row buildNewUsersRow(@Nonnull final SearchEntity entity) {
186186
private AnalyticsChart getNewUsersChart(OperationContext opContext) {
187187
try {
188188
final List<String> columns = ImmutableList.of("Name", "Title", "Email");
189-
final String newUsersTitle = "Active Users (Last 30 Days)";
189+
final String newUsersTitle = "New Users (Last 30 Days)";
190190
final SearchResult result = searchForNewUsers(opContext);
191191
final List<Row> newUserRows = new ArrayList<>();
192192
for (SearchEntity entity : result.getEntities()) {

datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/analytics/resolver/GetMetadataAnalyticsResolver.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ private List<AnalyticsChart> getCharts(MetadataAnalyticsInput input, OperationCo
7878

7979
SearchResult searchResult =
8080
_entityClient.searchAcrossEntities(
81-
opContext, entities, query, filter, 0, 0, Collections.emptyList(), null);
81+
opContext, entities, query, filter, 0, 0, Collections.emptyList());
8282

8383
List<AggregationMetadata> aggregationMetadataList =
8484
searchResult.getMetadata().getAggregations();

datahub-graphql-core/src/main/java/com/linkedin/datahub/graphql/resolvers/businessattribute/AddBusinessAttributeResolver.java

+2
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import static com.linkedin.datahub.graphql.resolvers.ResolverUtils.bindArgument;
44
import static com.linkedin.datahub.graphql.resolvers.mutate.MutationUtils.buildMetadataChangeProposalWithUrn;
5+
import static com.linkedin.datahub.graphql.resolvers.mutate.util.BusinessAttributeUtils.validateInputResources;
56
import static com.linkedin.metadata.Constants.BUSINESS_ATTRIBUTE_ASPECT;
67

78
import com.linkedin.businessattribute.BusinessAttributeAssociation;
@@ -43,6 +44,7 @@ public CompletableFuture<Boolean> get(DataFetchingEnvironment environment) throw
4344
return GraphQLConcurrencyUtils.supplyAsync(
4445
() -> {
4546
try {
47+
validateInputResources(resourceRefInputs, context);
4648
addBusinessAttributeToResource(
4749
context.getOperationContext(),
4850
businessAttributeUrn,

0 commit comments

Comments
 (0)