Skip to content
Merged
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
4 changes: 2 additions & 2 deletions .github/workflows/deploy-release.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,6 @@ jobs:
ORG_GPG_KEY_ID: ${{ secrets.ORG_GPG_KEY_ID }}
ORG_GPG_PASSPHRASE: ${{ secrets.ORG_GPG_PASSPHRASE }}
ORG_GPG_PRIVATE_KEY: ${{ secrets.ORG_GPG_PRIVATE_KEY }}
ORG_OSSRH_PASSWORD: ${{ secrets.ORG_OSSRH_PASSWORD }}
ORG_OSSRH_USERNAME: ${{ secrets.ORG_OSSRH_USERNAME }}
SONATYPE_PASSWORD: ${{ secrets.CENTRAL_SONATYPE_TOKEN_PASSWORD }}
SONATYPE_USERNAME: ${{ secrets.CENTRAL_SONATYPE_TOKEN_USERNAME }}
run: ./gradlew publishToSonatype closeAndReleaseSonatypeStagingRepository --no-configuration-cache
4 changes: 2 additions & 2 deletions .github/workflows/deploy-snapshot.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,6 @@ jobs:
ORG_GPG_KEY_ID: ${{ secrets.ORG_GPG_KEY_ID }}
ORG_GPG_PASSPHRASE: ${{ secrets.ORG_GPG_PASSPHRASE }}
ORG_GPG_PRIVATE_KEY: ${{ secrets.ORG_GPG_PRIVATE_KEY }}
ORG_OSSRH_PASSWORD: ${{ secrets.ORG_OSSRH_PASSWORD }}
ORG_OSSRH_USERNAME: ${{ secrets.ORG_OSSRH_USERNAME }}
SONATYPE_PASSWORD: ${{ secrets.CENTRAL_SONATYPE_TOKEN_PASSWORD }}
SONATYPE_USERNAME: ${{ secrets.CENTRAL_SONATYPE_TOKEN_USERNAME }}
run: ./gradlew publishToSonatype --no-configuration-cache
4 changes: 0 additions & 4 deletions .husky/commit-msg
Original file line number Diff line number Diff line change
@@ -1,7 +1,3 @@
#!/usr/bin/env sh

. "$(dirname "$0")/_/husky.sh"

readonly CURRENT_BRANCH=$(git symbolic-ref --short HEAD)

# Only check protected feature branche
Expand Down
10 changes: 10 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,16 @@

All notable changes to this project will be documented in this file. See [commit-and-tag-version](https://github.com/absolute-version/commit-and-tag-version) for commit guidelines.

## [0.4.1](https://github.com/eclipse-kuksa/kuksa-java-sdk/compare/release/release/v0.4.0...release/v0.4.1) (2026-09-17)

### Features

* Update KUKSA VAL v1 and v2 protobuf definitions ([509e4db](https://github.com/eclipse-kuksa/kuksa-java-sdk/commit/509e4db58ca3d992a418be408b09ee1a855b08e7))
* Update VSS spec to 6.0 and add hierarchical path resolution ([4742565](https://github.com/eclipse-kuksa/kuksa-java-sdk/commit/474256544bcff482a385ff536b495d94596dda47))

### Documentation

* Update broken KDoc class links and add AI usage notice ([8c7ddd0](https://github.com/eclipse-kuksa/kuksa-java-sdk/commit/8c7ddd0767ca7ecef7b6b416b6fdbb8cb9398fdb))
## [0.4.0](https://github.com/eclipse-kuksa/kuksa-java-sdk/compare/release/release/v0.3.2...release/v0.4.0) (2025-03-26)

### Features
Expand Down
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,13 @@

[![SDK:main <-> Databroker:main](https://github.com/eclipse-kuksa/kuksa-java-sdk/actions/workflows/daily_integration_main.yaml/badge.svg)](https://github.com/eclipse-kuksa/kuksa-java-sdk/actions/workflows/daily_integration_main.yaml?query=branch%3Amain)

> [!IMPORTANT]
> **AI Usage Notice**
>
> This repository partially contains AI-generated code using GitHub Copilot Business.
> This notice must remain attached to any reproduction of this repository.


This is a Java SDK for the [KUKSA Vehicle Abstraction Layer](https://github.com/eclipse-kuksa/kuksa-databroker).

## Overview
Expand Down
40 changes: 33 additions & 7 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023 - 2025 Contributors to the Eclipse Foundation
* Copyright (c) 2023 - 2026 Contributors to the Eclipse Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -22,7 +22,6 @@ import org.eclipse.kuksa.version.VERSION_FILE_DEFAULT_NAME
import org.eclipse.kuksa.version.VERSION_FILE_DEFAULT_PATH_KEY
import java.nio.file.FileVisitResult
import java.nio.file.Path
import kotlin.io.path.ExperimentalPathApi
import kotlin.io.path.bufferedWriter
import kotlin.io.path.createDirectories
import kotlin.io.path.createFile
Expand All @@ -49,8 +48,14 @@ plugins {
nexusPublishing {
repositories {
sonatype {
username = System.getenv("ORG_OSSRH_USERNAME")
password = System.getenv("ORG_OSSRH_PASSWORD")
val releaseUri = uri("https://ossrh-staging-api.central.sonatype.com/service/local/")
nexusUrl.set(releaseUri)

val snapshotUri = uri("https://central.sonatype.com/repository/maven-snapshots/")
snapshotRepositoryUrl.set(snapshotUri)

username = System.getenv("SONATYPE_USERNAME")
password = System.getenv("SONATYPE_PASSWORD")
}
}
}
Expand All @@ -69,21 +74,41 @@ subprojects {
// see: https://kotest.io/docs/framework/tags.html#gradle
tasks.withType<Test> {
val systemPropertiesMap = HashMap<String, Any>()
System.getProperties().forEach { key, value ->
System.getProperties().forEach { (key, value) ->
systemPropertiesMap[key.toString()] = value.toString()
}
systemProperties = systemPropertiesMap
}

// https://docs.gradle.org/current/userguide/dependency_locking.html
// update with: ./gradlew resolveAndLockAll --write-locks --update-locks '*:*' --no-configuration-cache
dependencyLocking {
lockAllConfigurations()
lockFile = file("$projectDir/gradle.lockfile")
}
}

@OptIn(ExperimentalPathApi::class)
// update with: ./gradlew resolveAndLockAll --write-locks --update-locks '*:*' --no-configuration-cache
tasks.register("resolveAndLockAll") {
group = "dependencies"
description = "Resolves and locks all dependencies for all subprojects."
notCompatibleWithConfigurationCache("Filters configurations at execution time")
doFirst {
require(gradle.startParameter.isWriteDependencyLocks) {
"$path must be run with --write-locks"
}
}
doLast {
allprojects.forEach { proj ->
proj.configurations
.filter { it.isCanBeResolved }
.forEach { it.resolve() }
}
}
}

tasks.register("mergeDashFiles") {
description = "Merges all dash files from subprojects into a single dash file in the build directory."
group = "oss"

dependsOn(
Expand Down Expand Up @@ -132,7 +157,8 @@ subprojects {
}
}

tasks.create("jacocoRootReport", JacocoReport::class.java) {
tasks.register("jacocoRootReport", JacocoReport::class.java) {
description = "Generates a Jacoco coverage report for all subprojects."
group = "report"

reports {
Expand Down
11 changes: 7 additions & 4 deletions buildSrc/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
/*
* Copyright (c) 2023 Contributors to the Eclipse Foundation
* Copyright (c) 2023 - 2026 Contributors to the Eclipse Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
Expand All @@ -17,6 +17,7 @@
*
*/

import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
Expand All @@ -26,12 +27,14 @@ plugins {

// Do not use Java Toolchains (yet).
tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = libs.versions.jvmTarget.get()
compilerOptions {
jvmTarget.set(JvmTarget.fromTarget(libs.versions.jvmTarget.get()))
}
}

java {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}

dependencies {
Expand Down
4 changes: 2 additions & 2 deletions buildSrc/src/main/kotlin/ktlint.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
*
*/

val ktlint by configurations.creating
val ktlint = configurations.create("ktlint")

dependencies {
// can't use Project.lib exension here because the plugin is applied before the versionCatalog is available
Expand All @@ -28,7 +28,7 @@ dependencies {
}
}

val ktlintCheck by tasks.registering(JavaExec::class) {
tasks.register<JavaExec>("ktlintCheck") {
group = LifecycleBasePlugin.VERIFICATION_GROUP
description = "Check Kotlin code style"
classpath = ktlint
Expand Down
37 changes: 27 additions & 10 deletions buildscripts/dash.sh
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
#!/usr/bin/env bash
#
# Copyright (c) 2023 Contributors to the Eclipse Foundation
# Copyright (c) 2023 - 2026 Contributors to the Eclipse Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
Expand All @@ -17,9 +18,17 @@
#
#

projectName=$1
folder=build/oss/"$projectName"
fileName=dependencies.txt
set -euo pipefail

projectPath=$1
# Normalize project path for gradle (ensure it starts with :)
gradleProjectPath=":${projectPath#:}"

# Normalize folder path (strip leading colon and replace colons with slashes)
folderPath="${projectPath#:}"
folderPath="${folderPath//://}"
folder="build/oss/$folderPath"
fileName="dependencies.txt"

mkdir -p "$folder"

Expand All @@ -42,16 +51,24 @@ mkdir -p "$folder"
unameOut="$(uname -s)"
case "${unameOut}" in
Linux*) GREP="grep";; # Linux
Darwin*) GREP="ggrep";; # Mac
Darwin*)
if command -v ggrep > /dev/null 2>&1; then
GREP="ggrep"
else
GREP="grep"
fi
;;
*) GREP="UNKNOWN:${unameOut}"
esac
echo "${GREP}"

./gradlew "$projectName":dependencies \
| ${GREP} -Poh "(?<=\-\-\- ).*" \
| ${GREP} -Pv "\([nc\*]\)" \
| ${GREP} -Pv "FAILED" \
| ${GREP} -Pv "project :[a-zA-Z0-9]+" \
deps_output=$(./gradlew "${gradleProjectPath}:dependencies")

echo "$deps_output" \
| ( ${GREP} -Poh "(?<=\-\-\- ).*" || true ) \
| ( ${GREP} -Pv "\([nc\*]\)" || true ) \
| ( ${GREP} -Pv "FAILED" || true ) \
| ( ${GREP} -Pv "project\s*[':]" || true ) \
| perl -pe 's/([\w\.\-]+):([\w\.\-]+):(?:[\w\.\-]+ -> )?([\w\.\-]+).*$/$1:$2:$3/gmi;t' \
| perl -pe 's/([\w\.\-]+):([\w\.\-]+) -> ([\w\.\-]+).*$/$1:$2:$3/gmi;t' \
| sort -u \
Expand Down
144 changes: 144 additions & 0 deletions buildscripts/generate-test-certificates-and-tokens.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,144 @@
#!/usr/bin/env bash
#
# Copyright (c) 2026 Contributors to the Eclipse Foundation
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
# SPDX-License-Identifier: Apache-2.0
#

set -euo pipefail

SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
ROOT_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"

AUTH_DIR="${ROOT_DIR}/kuksa-java-sdk/src/test/resources/authentication"
TLS_DIR="${ROOT_DIR}/kuksa-java-sdk/src/test/resources/tls"

mkdir -p "${AUTH_DIR}"
mkdir -p "${TLS_DIR}"

echo "==> Generating JWT authentication keys and tokens in ${AUTH_DIR}..."

python3 - <<EOF
import base64
import json
import os
import subprocess
import tempfile

def b64url(data: bytes) -> str:
return base64.urlsafe_b64encode(data).decode('ascii').rstrip('=')

tmpdir = tempfile.mkdtemp()
priv_key_path = os.path.join(tmpdir, 'jwt.key')
pub_key_path = '${AUTH_DIR}/jwt.key.pub'

# Generate 4096-bit RSA private key and export public key in PEM format
subprocess.run(['openssl', 'genrsa', '-out', priv_key_path, '4096'], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)
subprocess.run(['openssl', 'rsa', '-in', priv_key_path, '-pubout', '-out', pub_key_path], check=True, stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL)

# Valid until 2045-01-01T00:00:00Z
exp_timestamp = 2366841600

tokens = {
'actuate-provide-all': {
'sub': 'local dev',
'iss': 'createToken.py',
'aud': ['kuksa.val'],
'iat': 1516239022,
'exp': exp_timestamp,
'scope': 'actuate provide'
},
'provide-all': {
'sub': 'local dev',
'iss': 'createToken.py',
'aud': ['kuksa.val'],
'iat': 1516239022,
'exp': exp_timestamp,
'scope': 'provide'
},
'read-all': {
'sub': 'local dev',
'iss': 'createToken.py',
'aud': ['kuksa.val'],
'iat': 1516239022,
'exp': exp_timestamp,
'scope': 'read'
}
}

header = {'typ': 'JWT', 'alg': 'RS256'}
header_b64 = b64url(json.dumps(header, separators=(',', ':')).encode('utf-8'))

for name, payload in tokens.items():
payload_b64 = b64url(json.dumps(payload, separators=(',', ':')).encode('utf-8'))
signing_input = f'{header_b64}.{payload_b64}'.encode('utf-8')

p = subprocess.Popen(['openssl', 'dgst', '-sha256', '-sign', priv_key_path],
stdin=subprocess.PIPE, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
sig, err = p.communicate(signing_input)
if p.returncode != 0:
raise RuntimeError(f"Signing failed: {err.decode('utf-8')}")

token = f'{header_b64}.{payload_b64}.{b64url(sig)}'
with open(f'${AUTH_DIR}/{name}.token', 'w') as f:
f.write(token)

print("JWT tokens and public key successfully generated.")
EOF

echo "==> Generating TLS certificates in ${TLS_DIR}..."

TMP_DIR="$(mktemp -d)"
trap 'rm -rf "${TMP_DIR}"' EXIT

CA_KEY="${TMP_DIR}/CA.key"
CA_CERT="${TLS_DIR}/CA.pem"
SERVER_KEY="${TLS_DIR}/Server.key"
SERVER_CSR="${TMP_DIR}/Server.csr"
SERVER_CERT="${TLS_DIR}/Server.pem"
EXT_FILE="${TMP_DIR}/server.ext"

cat > "${EXT_FILE}" <<EOF
subjectAltName = @alt_names
basicConstraints = CA:FALSE
keyUsage = nonRepudiation, digitalSignature, keyEncipherment
extendedKeyUsage = serverAuth

[alt_names]
DNS.1 = Server
DNS.2 = localhost
IP.1 = 127.0.0.1
EOF

# 1. Generate CA private key and self-signed CA cert (valid 20 years = 7300 days)
openssl genrsa -out "${CA_KEY}" 2048 2>/dev/null
openssl req -x509 -new -nodes -key "${CA_KEY}" -sha256 -days 7300 \
-subj "/C=CA/ST=Ontario/L=Ottawa/O=Eclipse.org Foundation, Inc./CN=localhost-ca/emailAddress=kuksa-dev@eclipse.org" \
-out "${CA_CERT}" 2>/dev/null

# 2. Generate Server private key and CSR
openssl genrsa -out "${SERVER_KEY}" 2048 2>/dev/null
openssl req -new -key "${SERVER_KEY}" \
-subj "/C=CA/ST=Ontario/L=Ottawa/O=Eclipse.org Foundation, Inc./CN=Server/emailAddress=kuksa-dev@eclipse.org" \
-out "${SERVER_CSR}" 2>/dev/null

# 3. Sign Server certificate with CA (valid 20 years = 7300 days)
openssl x509 -req -in "${SERVER_CSR}" \
-CA "${CA_CERT}" -CAkey "${CA_KEY}" -CAcreateserial \
-out "${SERVER_CERT}" -days 7300 -sha256 \
-extfile "${EXT_FILE}" 2>/dev/null

echo "TLS CA and Server certificates successfully generated."
echo "==> Done!"
Loading
Loading