Skip to content

Commit

Permalink
XENOPS-1201 Dropped Alfresco 5 and 6; Added Alfresco 7.1, 7.2, 7.3, 7…
Browse files Browse the repository at this point in the history
….4; Dropped secret in favor of TLS; Dropped obsolete Jar shadowing; Dropped obsolete boms; Fixed log4j2 bug (limited to docker compose and minimal log4j2.properties config; Fixed bug in integration test where files used for testing were no longer available;
  • Loading branch information
todorinskiz committed Dec 20, 2024
1 parent 61c604a commit 66a1f13
Show file tree
Hide file tree
Showing 20 changed files with 235 additions and 69 deletions.
5 changes: 3 additions & 2 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,12 @@ jobs:
run: ./gradlew javadoc
integration-test:
runs-on: ubuntu-latest
if: ${{ github.ref == 'refs/heads/master' || github.base_ref == 'master' || startsWith(github.ref, 'refs/tags/') }}
# Disable temporarily
# if: ${{ github.ref == 'refs/heads/master' || github.base_ref == 'master' || startsWith(github.ref, 'refs/tags/') }}
strategy:
matrix:
flavour: [ "community" ] ## , "enterprise"
version: [ "70", "71", "72", "73", "74" ]
version: [ "71", "72", "73", "74" ]
steps:
- uses: actions/checkout@v4
with:
Expand Down
11 changes: 10 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
---
title: Changelog - Alfred Health Processor
date: 19 December 2024
date: 20 December 2024
report: true
colorlinks: true
---
Expand All @@ -22,6 +22,15 @@ Version template:

# Alfresco Health Processor Changelog

## [0.6.0] - UNRELEASED

### Added
* Alfresco 7.1, 7.2, 7.3, 7.4 support

### Removed
* Alfresco 5 & 6 support


## [0.5.6] - 2024-12-19

### Fixed
Expand Down
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,9 @@ eu.xenit.alfresco.healthprocessor.plugin.content-validation.properties=cm:conten
If this property is not set (which is the default), the plugin will request all properties of type `d:content`
from Alfresco's `DictionaryService`.

When validating content, "NONE" in the reporting means, there is no status for a certain document, because it was not checked.
For example, content checks report nodes without any content property as none.

#### Solr index Validation

Activation property: `eu.xenit.alfresco.healthprocessor.plugin.solr-index.enabled=true`
Expand Down Expand Up @@ -286,7 +289,11 @@ Activation property: `eu.xenit.alfresco.healthprocessor.reporter.log.summary.ena
A simple implementation that writes, once a Health Processor cycle is completed, a summary and unhealthy nodes to the
Alfresco logs.

Relevant logger: `log4j.logger.eu.xenit.alfresco.healthprocessor.reporter.log.SummaryLoggingHealthReporter=INFO`
> [!WARNING]
> Starting from alfresco 7.4, alfresco has migrated to log4j2. The original log4j logger will no longer exist.
Relevant logger (log4j) (pre Alfresco 7.3): `log4j.logger.eu.xenit.alfresco.healthprocessor.reporter.log.SummaryLoggingHealthReporter=INFO`
Relevant logger (log4j2): `logger.eu_xenit_alfresco_healthprocessor.name=eu.xenit.alfresco.healthprocessor`

Example output:

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
logger.eu_xenit_alfresco_healthprocessor.name=eu.xenit.alfresco.healthprocessor
logger.eu_xenit_alfresco_healthprocessor.level=info
logger.eu_xenit_alfresco_healthprocessor_indexing.name=eu.xenit.alfresco.healthprocessor.indexing
logger.eu_xenit_alfresco_healthprocessor_fixer.name=eu.xenit.alfresco.healthprocessor.fixer
logger.eu_xenit_alfresco_healthprocessor_plugins.name=eu.xenit.alfresco.healthprocessor.plugins
logger.eu_xenit_alfresco_healthprocessor_processing.name=eu.xenit.alfresco.healthprocessor.processing
logger.eu_xenit_alfresco_healthprocessor_reporter.name=eu.xenit.alfresco.healthprocessor.reporter
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,11 @@ eu.xenit.alfresco.healthprocessor.plugin.solr-index.enabled=false
eu.xenit.alfresco.healthprocessor.plugin.solr-index.check-transaction=false
eu.xenit.alfresco.healthprocessor.plugin.solr-index.endpoints=default,archive
eu.xenit.alfresco.healthprocessor.plugin.solr-index.endpoints.default.type=Always
eu.xenit.alfresco.healthprocessor.plugin.solr-index.endpoints.default.base-uri=http://${solr.host}:${solr.port}/solr/alfresco
eu.xenit.alfresco.healthprocessor.plugin.solr-index.endpoints.default.base-uri=https://${solr.host}:${solr.port.ssl}/solr/alfresco
eu.xenit.alfresco.healthprocessor.plugin.solr-index.endpoints.default.indexed-store=workspace://SpacesStore

eu.xenit.alfresco.healthprocessor.plugin.solr-index.endpoints.archive.type=Always
eu.xenit.alfresco.healthprocessor.plugin.solr-index.endpoints.archive.base-uri=http://${solr.host}:${solr.port}/solr/archive
eu.xenit.alfresco.healthprocessor.plugin.solr-index.endpoints.archive.base-uri=https://${solr.host}:${solr.port.ssl}/solr/archive
eu.xenit.alfresco.healthprocessor.plugin.solr-index.endpoints.archive.indexed-store=archive://SpacesStore

eu.xenit.alfresco.healthprocessor.reporter.store.max-stored-reports=3000
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,8 @@

<bean id="eu.xenit.alfresco.healthprocessor.plugins.solr.SolrRequestExecutor"
class="eu.xenit.alfresco.healthprocessor.plugins.solr.SolrRequestExecutor" >
<constructor-arg name="checkTransaction" value="${eu.xenit.alfresco.healthprocessor.plugin.solr-index.check-transaction}" />
<constructor-arg name="checkTransaction" value="${eu.xenit.alfresco.healthprocessor.plugin.solr-index.check-transaction}" />
<constructor-arg name="globalProperties" ref="global-properties" />
</bean>

<bean id="eu.xenit.alfresco.healthprocessor.plugins.solr.endpoint.SearchEndpointSelector"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,6 @@

import com.fasterxml.jackson.databind.JsonNode;
import eu.xenit.alfresco.healthprocessor.plugins.solr.endpoint.SearchEndpoint;
import java.io.IOException;
import java.util.Collection;
import java.util.Map;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
Expand All @@ -17,7 +11,14 @@
import org.apache.http.client.HttpClient;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpUriRequest;
import org.apache.http.impl.client.HttpClientBuilder;

import java.io.IOException;
import java.util.Collection;
import java.util.Map;
import java.util.Properties;
import java.util.function.Function;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;


/**
Expand All @@ -26,11 +27,12 @@
@Slf4j
@RequiredArgsConstructor
public class SolrRequestExecutor {

private final HttpClient httpClient;
private final boolean checkTransaction;

public SolrRequestExecutor(Boolean checkTransaction) {
this(HttpClientBuilder.create().build(), checkTransaction);
public SolrRequestExecutor(Boolean checkTransaction, Properties globalProperties) {
this(SslHttpClientFactory.setupHttpClient(globalProperties), checkTransaction);
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,84 @@
package eu.xenit.alfresco.healthprocessor.plugins.solr;

import org.apache.http.client.HttpClient;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.ssl.SSLContexts;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.security.cert.CertificateException;
import java.util.Objects;
import java.util.Properties;

public class SslHttpClientFactory {

public static HttpClient setupHttpClient(Properties globalProperties) {
try {
String keystoreLocation = globalProperties.getProperty("encryption.ssl.keystore.location");
String truststoreLocation = globalProperties.getProperty("encryption.ssl.truststore.location");

File keystoreParentLocation = new File(keystoreLocation).getParentFile();
String keystorePassword = Objects.toString(getKeystorePassword(keystoreParentLocation));

// Load the KeyStore
KeyStore keyStore = KeyStore.getInstance("JCEKS");
try (FileInputStream keystoreFile = new FileInputStream(keystoreLocation)) {
keyStore.load(keystoreFile, keystorePassword.toCharArray());
}

// Load the TrustStore
String truststorePassword = Objects.toString(getTruststorePassword(keystoreParentLocation));
KeyStore trustStore = KeyStore.getInstance("JCEKS");
try (FileInputStream truststoreFile = new FileInputStream(truststoreLocation)) {
trustStore.load(truststoreFile, truststorePassword.toCharArray());
}

// Build SSLContext
// If the key password is different from the keystore password,
// retrieve it similarly if specified (else assume same)
char[] keyPasswordChars = keystorePassword.toCharArray();

javax.net.ssl.SSLContext sslContext = SSLContexts.custom()
.loadKeyMaterial(keyStore, keyPasswordChars)
.loadTrustMaterial(trustStore, (chain, authType) -> true) // Use default trust strategy
.build();

// Create the SSLConnectionSocketFactory with the SSLContext
SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(
sslContext,
new String[]{"TLSv1.2","TLSv1.3"}, // Allowed TLS protocols
null, // Default cipher suites
NoopHostnameVerifier.INSTANCE
);
return HttpClientBuilder.create()
.setSSLHostnameVerifier(NoopHostnameVerifier.INSTANCE)
.setSSLSocketFactory(sslSocketFactory)
.build();
} catch (IOException | CertificateException | KeyManagementException | UnrecoverableKeyException |
KeyStoreException | NoSuchAlgorithmException e) {
throw new RuntimeException(e);
}
}

private static Object getKeystorePassword(File keystoreParentLocation) throws IOException {
Properties p = new Properties();
p.load(new FileInputStream(keystoreParentLocation.getAbsolutePath()
+ "/ssl-keystore-passwords.properties"));
return p.get("keystore.password");
}

private static Object getTruststorePassword(File keystoreParentLocation) throws IOException {
Properties p = new Properties();
p.load(new FileInputStream(keystoreParentLocation.getAbsolutePath()
+ "/ssl-truststore-passwords.properties"));
return p.get("keystore.password");
}
}
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
package eu.xenit.alfresco.healthprocessor.plugins.solr;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

import com.github.paweladamski.httpclientmock.HttpClientMock;
import eu.xenit.alfresco.healthprocessor.plugins.solr.SolrRequestExecutor.SolrNodeCommand;
import eu.xenit.alfresco.healthprocessor.plugins.solr.SolrRequestExecutor.SolrActionResponse;
import eu.xenit.alfresco.healthprocessor.plugins.solr.SolrRequestExecutor.SolrNodeCommand;
import eu.xenit.alfresco.healthprocessor.plugins.solr.endpoint.SearchEndpoint;
import eu.xenit.alfresco.healthprocessor.util.SetUtil;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeRef.Status;
import org.alfresco.service.cmr.repository.StoreRef;
import org.apache.http.client.HttpResponseException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import java.io.IOException;
import java.net.URI;
import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.UUID;
import java.util.stream.Collectors;
import org.alfresco.service.cmr.repository.NodeRef;
import org.alfresco.service.cmr.repository.NodeRef.Status;
import org.alfresco.service.cmr.repository.StoreRef;
import org.apache.http.client.HttpResponseException;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTrue;

class SolrRequestExecutorTest {

Expand Down
20 changes: 11 additions & 9 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
plugins {
id 'eu.xenit.alfresco' version '1.2.0' apply(false)
id 'eu.xenit.docker-alfresco' version '5.5.0' apply(false)
id "org.sonarqube" version "3.3"
id "org.kordamp.gradle.jacoco" version "0.47.0"
id "org.sonarqube" version "5.1.0.4882"
id "org.kordamp.gradle.jacoco" version "0.54.0"
id "be.vbgn.ci-detect" version "0.5.0"
}

//description = "Alfresco Health Processor: A background processor capable of performing various operations on the nodes in your Alfresco repository, in a batched and controlled manner"
Expand All @@ -13,16 +14,17 @@ sonarqube {
property "sonar.organization", "xenit-eu"
property "sonar.host.url", "https://sonarcloud.io"
property "sonar.coverage.exclusions", "**/eu/xenit/alfresco/healthprocessor/example/*"
if (ci.isPullRequest()) {
property "sonar.pullrequest.key", ci.pullRequest
property "sonar.pullrequest.branch", ci.branch
property "sonar.pullrequest.base", ci.pullRequestTargetBranch
} else {
// GIT_BRANCH allows to push from local development directly to SonarCloud
property "sonar.branch.name", ci.reference != null ? ci.reference : "$System.env.GIT_BRANCH"
}
}
}

ext {
alfrescoVersion = '7.0.0'
alfredTelemetryVersion = '0.6.0'
micrometerVersion = '1.0.6'
lombokVersion = '1.18.36'
}

subprojects {

plugins.withType(JavaBasePlugin) {
Expand Down
8 changes: 7 additions & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1 +1,7 @@
reckon.scope=patch
reckon.scope=patch
alfrescoVersion=7.1.0
alfredTelemetryVersion=0.10.1
micrometerVersion=1.0.6
jvmExtrasVersion=0.1.2
lombokVersion=1.18.36
ootbVersion=1.2.2.0
6 changes: 0 additions & 6 deletions integration-tests/alfresco-community-70/overload.gradle

This file was deleted.

6 changes: 0 additions & 6 deletions integration-tests/alfresco-enterprise-70/overload.gradle

This file was deleted.

19 changes: 15 additions & 4 deletions integration-tests/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ ext {

dependencies {
alfrescoProvided project(":alfresco-health-processor-platform")
// alfrescoProvided(enforcedPlatform("eu.xenit.alfresco:alfresco-community-bom:${alfrescoVersion}"))
alfrescoProvided platform("org.alfresco:acs-community-packaging:${alfrescoVersion}")
alfrescoProvided("org.alfresco:alfresco-repository") {
exclude module: 'spring-social-facebook-web'
Expand All @@ -23,9 +22,6 @@ dependencies {
testImplementation "org.hamcrest:hamcrest-all:${hamcrestVersion}"
testImplementation "io.rest-assured:rest-assured:${restAssuredVersion}"
testImplementation "org.awaitility:awaitility:${awaitilityVersion}"

testImplementation group: 'org.slf4j', name: 'slf4j-api', version: "${slf4jVersion}"
testImplementation group: 'org.slf4j', name: 'slf4j-simple', version: "${slf4jVersion}"
}

test {
Expand Down Expand Up @@ -60,6 +56,12 @@ subprojects { Project p ->
apply plugin: 'eu.xenit.docker-alfresco'
apply plugin: 'eu.xenit.docker-compose.auto'

configurations {
all {
exclude group: 'org.slf4j'
}
}

dependencies {
if (project.hasProperty("alfrescoBaseWarBom")) {
baseAlfrescoWar platform("${alfrescoBaseWarBom}")
Expand All @@ -68,7 +70,16 @@ subprojects { Project p ->
alfrescoAmp project(path: ":integration-tests", configuration: "amp")
alfrescoAmp project(path: ":alfresco-health-processor-platform", configuration: "amp")
alfrescoAmp "eu.xenit.alfred.telemetry:alfred-telemetry-platform:${alfredTelemetryVersion}@amp"

alfrescoAmp("org.orderofthebee.support-tools:support-tools-repo:${ootbVersion}:amp@amp")
alfrescoSM(group: 'org.postgresql', name: 'postgresql', version: '42.6.0')

alfrescoSM "io.micrometer:micrometer-core:${micrometerVersion}"
alfrescoSM "io.github.mweirauch:micrometer-jvm-extras:${jvmExtrasVersion}"

alfrescoSM "io.micrometer:micrometer-registry-graphite:${micrometerVersion}"
alfrescoSM "io.micrometer:micrometer-registry-jmx:${micrometerVersion}"
alfrescoSM "io.micrometer:micrometer-registry-prometheus:${micrometerVersion}"
}

dockerBuild {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
parent="webscript">
<constructor-arg name="nodeFinder" ref="nodeFinder" />
<constructor-arg name="endpointSelector" ref="eu.xenit.alfresco.healthprocessor.plugins.solr.endpoint.SearchEndpointSelector" />
<constructor-arg name="globalProperties" ref="global-properties" />
</bean>
<bean id="solr.CheckWebScript"
class="eu.xenit.alfresco.healthprocessor.solr.SolrCheckNodeWebScript"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public class NodeFinder {
private final SearchService searchService;
private final NamespaceService namespaceService;

private static final String XPATH = "/app:company_home/st:sites/cm:swsdp/cm:documentLibrary/cm:Agency_x0020_Files/cm:Images/*";
private static final String XPATH = "/app:company_home/app:dictionary/app:content_templates/*";

public NodeFinder(NodeService nodeService, SearchService searchService,
NamespaceService namespaceService) {
Expand Down
Loading

0 comments on commit 66a1f13

Please sign in to comment.