Skip to content

BE: Allow disabling GitHub release info #1108

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import static io.kafbat.ui.api.model.AuthType.DISABLED;
import static io.kafbat.ui.api.model.AuthType.OAUTH2;
import static io.kafbat.ui.model.ApplicationInfoDTO.EnabledFeaturesEnum;
import static io.kafbat.ui.util.GithubReleaseInfo.GITHUB_RELEASE_INFO_ENABLED;
import static io.kafbat.ui.util.GithubReleaseInfo.GITHUB_RELEASE_INFO_TIMEOUT;

import com.google.common.annotations.VisibleForTesting;
Expand All @@ -15,12 +16,14 @@
import io.kafbat.ui.model.OAuthProviderDTO;
import io.kafbat.ui.util.DynamicConfigOperations;
import io.kafbat.ui.util.GithubReleaseInfo;
import jakarta.annotation.Nullable;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import java.util.Properties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.info.BuildProperties;
Expand All @@ -33,7 +36,9 @@
import org.springframework.stereotype.Service;

@Service
@Slf4j
public class ApplicationInfoService {
@Nullable
private final GithubReleaseInfo githubReleaseInfo;
private final ApplicationContext applicationContext;
private final DynamicConfigOperations dynamicConfigOperations;
Expand All @@ -44,36 +49,52 @@ public ApplicationInfoService(DynamicConfigOperations dynamicConfigOperations,
ApplicationContext applicationContext,
@Autowired(required = false) BuildProperties buildProperties,
@Autowired(required = false) GitProperties gitProperties,
@Value("${" + GITHUB_RELEASE_INFO_ENABLED + ":true}") boolean githubInfoEnabled,
@Value("${" + GITHUB_RELEASE_INFO_TIMEOUT + ":10}") int githubApiMaxWaitTime) {
this.applicationContext = applicationContext;
this.dynamicConfigOperations = dynamicConfigOperations;
this.buildProperties = Optional.ofNullable(buildProperties).orElse(new BuildProperties(new Properties()));
this.gitProperties = Optional.ofNullable(gitProperties).orElse(new GitProperties(new Properties()));
githubReleaseInfo = new GithubReleaseInfo(githubApiMaxWaitTime);
if (githubInfoEnabled) {
this.githubReleaseInfo = new GithubReleaseInfo(githubApiMaxWaitTime);
} else {
this.githubReleaseInfo = null;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

let's either mark the field as nullable or replace it with some empty object instead to prevent NPEs

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's also output a bold warning into logs on startup in case this is disabled that running outdated versions is dangerous due to CVEs and we will not provide support for outdated versions per our security policy

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's also output a bold warning into logs on startup ...

A real "warning", i.e. WARN log level? INFO ... OK, but warning seems little overdone. I'm running about 400 instances in various test clusters and remote systems, no online access, updates and security scans are done by external tooling. Simply shifting Firewall/eBPF warnings to application warnings was not what I had in mind....

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It might seem "overdone" until folks start coming up with air-gapped installations requesting support for 2 yo releases.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I get the point. But does a warning really prevent these folks from requesting anything? My experience is you can write "UNMAINTEINED" in 50px bold at the top of a GH issue template and you still get new tickets with the warning not even removed 🤷‍♂️

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nevertheless I've added a log warning. (yet another one to ignore, but at least consistent with other config scenarios).

WARN  [restartedMain] i.k.u.s.ApplicationInfoService: Check for latest release is disabled. Note that old versions are not supported, please make sure that your system is up to date.

log.warn("Check for latest release is disabled."
+ " Note that old versions are not supported, please make sure that your system is up to date.");
}
}

public ApplicationInfoDTO getApplicationInfo() {
var releaseInfo = githubReleaseInfo.get();
var releaseInfo = githubReleaseInfo != null ? githubReleaseInfo.get() : null;
return new ApplicationInfoDTO()
.build(getBuildInfo(releaseInfo))
.enabledFeatures(getEnabledFeatures())
.latestRelease(convert(releaseInfo));
}

@Nullable
private ApplicationInfoLatestReleaseDTO convert(GithubReleaseInfo.GithubReleaseDto releaseInfo) {
if (releaseInfo == null) {
return null;
}
return new ApplicationInfoLatestReleaseDTO()
.htmlUrl(releaseInfo.html_url())
.publishedAt(releaseInfo.published_at())
.versionTag(releaseInfo.tag_name());
}

private ApplicationInfoBuildDTO getBuildInfo(GithubReleaseInfo.GithubReleaseDto release) {
return new ApplicationInfoBuildDTO()
.isLatestRelease(release.tag_name() != null && release.tag_name().equals(buildProperties.getVersion()))
var buildInfo = new ApplicationInfoBuildDTO()
.commitId(gitProperties.getShortCommitId())
.version(buildProperties.getVersion())
.buildTime(buildProperties.getTime() != null
? DateTimeFormatter.ISO_INSTANT.format(buildProperties.getTime()) : null);
if (release != null) {
buildInfo = buildInfo.isLatestRelease(
release.tag_name() != null && release.tag_name().equals(buildProperties.getVersion())
);
}
return buildInfo;
}

private List<EnabledFeaturesEnum> getEnabledFeatures() {
Expand Down Expand Up @@ -119,10 +140,13 @@ private List<OAuthProviderDTO> getOAuthProviders() {
// updating on startup and every hour
@Scheduled(fixedRateString = "${github-release-info-update-rate:3600000}")
public void updateGithubReleaseInfo() {
githubReleaseInfo.refresh().subscribe();
if (githubReleaseInfo != null) {
githubReleaseInfo.refresh().subscribe();
}
}

@VisibleForTesting
@Nullable
GithubReleaseInfo githubReleaseInfo() {
return githubReleaseInfo;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

@Slf4j
public class GithubReleaseInfo {
public static final String GITHUB_RELEASE_INFO_ENABLED = "github.release.info.enabled";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please document this property in the docs too: https://github.com/kafbat/ui-docs

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done: kafbat/ui-docs#56

Also added the 2 pre-existing properties for this feature (timeout, update-rate)

public static final String GITHUB_RELEASE_INFO_TIMEOUT = "github.release.info.timeout";

private static final String GITHUB_LATEST_RELEASE_RETRIEVAL_URL =
Expand Down
Original file line number Diff line number Diff line change
@@ -1,17 +1,43 @@
package io.kafbat.ui.service;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertNull;

import io.kafbat.ui.AbstractIntegrationTest;
import io.kafbat.ui.util.DynamicConfigOperations;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;

class ApplicationInfoServiceTest extends AbstractIntegrationTest {
@Autowired
private ApplicationInfoService service;

@Autowired
private DynamicConfigOperations dynamicConfigOperations;

@Test
void testCustomGithubReleaseInfoTimeout() {
assertEquals(100, service.githubReleaseInfo().getGithubApiMaxWaitTime());
}

@Test
void testDisabledReleaseInfo() {
var service2 = new ApplicationInfoService(
dynamicConfigOperations,
null,
null,
null,
false,
101
);

assertNull(service2.githubReleaseInfo(), "unexpected GitHub release info when disabled");
var appInfo = service2.getApplicationInfo();
assertNotNull(appInfo, "application info must not be NULL");
assertNull(appInfo.getLatestRelease(), "latest release should be NULL when disabled");
assertNotNull(appInfo.getBuild(), "build info must not be NULL");
assertNotNull(appInfo.getEnabledFeatures(), "enabled features must not be NULL");
}

}
10 changes: 9 additions & 1 deletion frontend/src/components/Version/Version.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import WarningIcon from 'components/common/Icons/WarningIcon';
import { gitCommitPath } from 'lib/paths';
import { useLatestVersion } from 'lib/hooks/api/latestVersion';
import { formatTimestamp } from 'lib/dateTimeHelpers';
import { useTheme } from 'styled-components';

import * as S from './Version.styled';

Expand All @@ -17,9 +18,16 @@ const Version: React.FC = () => {
? versionTag
: formatTimestamp(buildTime);

const theme = useTheme();

return (
<S.Wrapper>
{!isLatestRelease && (
{isLatestRelease === null && (
<S.OutdatedWarning title="Version check disabled.">
<WarningIcon color={theme.icons.infoIcon} />
</S.OutdatedWarning>
)}
{isLatestRelease === false && (
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd like to see a visual difference between "no latest release present" and "user disabled version check" in the UI. This is crucial as it's often only the UI screenshots I have to deduct things from.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any suggestion how such information should look?

Frankly, I don't see any benefit in such information. Currently running version is displayed, if the check failed there's a warning symbol and the information if there's an update available or not can change 1 second after a screenshot was taken, because it's dynamic info.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Perhaps a red (rather than yellow) exclamation mark icon (most likely it's an svg, so altering stroke-color should work) with a different text about version check disabled.
The benefit is offloading responsibility of running an oudated and possibly CVE-"enriched" version and giving the maintainers visual signal of what the user's running (red icon -> no version check = most likely outdated -> no support)

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A red warning, really?

I've learned to ignore the yellow icon due do failing version checks and yet there are frequent questions if there's something wrong. So annoying users, who have no control whatsoever about the deployed version in our case, with read warning sign that typically means "something is wrong here" ...

Our use case are - you guessed it - isolated systems, mostly dev/staging environments. We allow users some access to the underlying Kafka and deployment/updates are done by some automation/opt team who don't see the UI warnings anyway.

We were looking for a solution to remove the frontend warning, not making it look worse.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You wouldn't imagine the number of issues I've seen where people come with their "up-to-date" installations, only to realize after wasting some time that it's not only an outdated version, but also a fork with completely unrelated functionality that we don't even have. Not sure of a middle ground here. @germanosin thoughts?

Copy link
Author

@stklcode stklcode May 29, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

On the oder end, I've seen questions from users about the warning of "UNKNOWN" version and regular tickets from ops about log warnings that nobody can do anything about.

We have filters on our network logs to prevent alerting from unauthorized access attempts and injected a logging config to suppress the "Authentication is disabled" warning for instances running behind an external auth gateway. But we cannot filter the human eye and regular "just ignore the warning" is not really a satisfactory answer.


Evaluated red and gray symbol (current yellow and none for reference). My preference is "none" or maybe gray 😉

kafkaui_versioncheck

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My personal preference: gray

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I extended the <WarningIcon> component to (a) use theme's warningIcon color instead of hardcoded color (was #F2C94C, now #FFDD57 ... close enough for me) and (b) allow override by parameter.

Override to infoIcon color (#ABB5BA) with adjusted message in case the check info is not available.

<S.OutdatedWarning
title={`Your app version is outdated. Latest version is ${
versionTag || 'UNKNOWN'
Expand Down
7 changes: 4 additions & 3 deletions frontend/src/components/common/Icons/WarningIcon.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import React from 'react';
import styled from 'styled-components';
import styled, { useTheme } from 'styled-components';

const WarningIconContainer = styled.span`
align-items: center;
Expand All @@ -9,7 +9,8 @@ const WarningIconContainer = styled.span`
width: 1.5rem;
`;

const WarningIcon: React.FC = () => {
const WarningIcon: React.FC<{ color?: string }> = ({ color }) => {
const theme = useTheme();
return (
<WarningIconContainer>
<svg
Expand All @@ -24,7 +25,7 @@ const WarningIcon: React.FC = () => {
fillRule="evenodd"
clipRule="evenodd"
d="M8.09265 1.06679C7.60703 0.250524 6.39297 0.250524 5.90735 1.06679L0.170916 10.7089C-0.314707 11.5252 0.292322 12.5455 1.26357 12.5455H12.7364C13.7077 12.5455 14.3147 11.5252 13.8291 10.7089L8.09265 1.06679ZM6 5.00006C6 4.44778 6.44772 4.00006 7 4.00006C7.55228 4.00006 8 4.44778 8 5.00006V7.00006C8 7.55235 7.55228 8.00006 7 8.00006C6.44772 8.00006 6 7.55235 6 7.00006V5.00006ZM6 10.0001C6 9.44778 6.44772 9.00006 7 9.00006C7.55228 9.00006 8 9.44778 8 10.0001C8 10.5523 7.55228 11.0001 7 11.0001C6.44772 11.0001 6 10.5523 6 10.0001Z"
fill="#F2C94C"
fill={color || theme.icons.warningIcon}
/>
</svg>
</WarningIconContainer>
Expand Down
Loading