diff --git a/.github/dependabot.yml b/.github/dependabot.yml index 61cf9ae..479cfd8 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -3,7 +3,7 @@ updates: - package-ecosystem: "gradle" directory: "/" schedule: - interval: "monthly" + interval: "weekly" open-pull-requests-limit: 10 groups: test: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 34be7b8..d8fa15d 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -7,7 +7,7 @@ on: jobs: build-and-release: - runs-on: ubuntu-latest + runs-on: ubuntu-22.04 permissions: contents: write @@ -26,8 +26,9 @@ jobs: env: VERSION: ${{ steps.get_version.outputs.VERSION }} run: | - echo "version=$VERSION" > gradle.properties - echo "gradle.properties criado:" + # Version an bestehendes gradle.properties anhängen (nicht überschreiben) + echo "version=$VERSION" >> gradle.properties + echo "gradle.properties updated:" cat gradle.properties - name: Set up JDK 17 @@ -44,7 +45,7 @@ jobs: run: ./gradlew specsValidation - name: Build with Gradle - run: ./gradlew build + run: ./gradlew build --write-verification-metadata sha256 - name: Validate Maven Central credentials run: | @@ -60,23 +61,26 @@ jobs: run: curl --version - name: Publish to Maven Central - run: ./gradlew publishToMavenCentral + run: ./gradlew publishToMavenCentral --write-verification-metadata sha256 env: MAVEN_CENTRAL_TOKEN: ${{ secrets.MAVEN_CENTRAL_TOKEN }} GPG_PRIVATE_KEY: ${{ secrets.GPG_PRIVATE_KEY }} GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} + - name: Generate SBOM + run: ./gradlew cyclonedxBom + - name: Update README version run: | VERSION=${{ steps.get_version.outputs.VERSION }} sed -i "s/jtoon:[0-9]\+\.[0-9]\+\.[0-9]\+/jtoon:$VERSION/g" README.md sed -i "s/[0-9]\+\.[0-9]\+\.[0-9]\+<\/version>/$VERSION<\/version>/g" README.md - - name: Commit README changes + - name: Commit README and verification metadata changes run: | git config user.name "github-actions[bot]" git config user.email "github-actions[bot]@users.noreply.github.com" - git add README.md build.gradle + git add README.md build.gradle gradle/verification-metadata.xml git diff --staged --quiet || git commit -m "docs: update version to ${{ steps.get_version.outputs.VERSION }} in README" git push origin main env: @@ -85,7 +89,9 @@ jobs: - name: Create GitHub Release uses: softprops/action-gh-release@v3.0.1 with: - files: build/libs/*.jar + files: | + build/libs/*.jar + build/reports/jtoon-bom.json generate_release_notes: true draft: false prerelease: ${{ contains(steps.get_version.outputs.VERSION, '-') }} @@ -113,4 +119,5 @@ jobs: path: | build/libs/*.jar build/reports/tests/test/ + build/reports/jtoon-bom.json retention-days: 30 diff --git a/.gitignore b/.gitignore index 3512a58..e94b00b 100644 --- a/.gitignore +++ b/.gitignore @@ -43,3 +43,9 @@ bin/ ### Mac OS ### .DS_Store /.idea/ + +### Secrets & Logs ### +*.log +*.pem +*.key +*.env diff --git a/build.gradle b/build.gradle index bf481e1..03124f5 100644 --- a/build.gradle +++ b/build.gradle @@ -6,6 +6,8 @@ plugins { id 'com.github.spotbugs' version '6.5.8' id 'pmd' id 'checkstyle' + id 'org.owasp.dependencycheck' version '12.2.2' + id 'org.cyclonedx.bom' version '3.2.4' id 'info.solidsoft.pitest' version '1.19.0' } @@ -57,6 +59,7 @@ spotbugs { } tasks.spotbugsMain { + ignoreFailures = false reports { html { required = true @@ -114,6 +117,19 @@ checkstyle { ignoreFailures = true } +dependencyCheck { + skip = System.getenv('CI') == 'true' + formats = ['HTML', 'XML'] + suppressionFile = file('dependency-check-suppressions.xml') + skipTestGroups = false // include test dependencies in analysis +} + +tasks.cyclonedxBom { + projectType = 'library' + jsonOutput.set(file("build/reports/jtoon-bom.json")) + xmlOutput.unsetConvention() +} + tasks.checkstyleMain { reports { xml.required = true diff --git a/dependency-check-suppressions.xml b/dependency-check-suppressions.xml new file mode 100644 index 0000000..fbf9371 --- /dev/null +++ b/dependency-check-suppressions.xml @@ -0,0 +1,3 @@ + + + diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..e97b51c --- /dev/null +++ b/gradle.properties @@ -0,0 +1,10 @@ +# ---- Build Performance ---- +org.gradle.configuration-cache=true +org.gradle.caching=true +org.gradle.parallel=true +org.gradle.daemon=true +org.gradle.jvmargs=-Xmx2048m -XX:MaxMetaspaceSize=512m -Dfile.encoding=UTF-8 + +# ---- Reproducible Builds ---- +# Remove build time from JAR manifests for bit-identical outputs +systemProp.org.gradle.internal.launcher.welcomeMessageEnabled=false diff --git a/gradle/publishing.gradle b/gradle/publishing.gradle index d40af15..273eceb 100644 --- a/gradle/publishing.gradle +++ b/gradle/publishing.gradle @@ -95,10 +95,7 @@ tasks.register('publishToMavenCentral') { println "Uploading bundle to Maven Central Portal..." println "Bundle file: ${bundleFile.absolutePath} (${bundleFile.length()} bytes)" - println "Token length: ${token.length()} characters" - println "Token starts with: ${token.take(15)}..." - println "Token ends with: ...${token.takeRight(15)}" - + // Create a temporary file to capture the response def responseFile = File.createTempFile("maven-central-response", ".json") responseFile.deleteOnExit() diff --git a/gradle/verification-metadata.xml b/gradle/verification-metadata.xml new file mode 100644 index 0000000..431b39d --- /dev/null +++ b/gradle/verification-metadata.xml @@ -0,0 +1,2692 @@ + + + + true + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/gradle/verification.gradle b/gradle/verification.gradle index 0f1be56..932f77d 100644 --- a/gradle/verification.gradle +++ b/gradle/verification.gradle @@ -14,10 +14,7 @@ tasks.register('testMavenCentralAuth') { } println "Testing Maven Central Portal authentication..." - println "Token length: ${token.length()} characters" - println "Token starts with: ${token.take(15)}..." - println "Token ends with: ...${token.takeRight(15)}" - + // Test with a simple GET request to check authentication // Using the deployments list endpoint which is known to work def testUrl = 'https://central.sonatype.com/api/v1/publisher/deployments' diff --git a/gradle/wrapper/gradle-wrapper.jar.sha256 b/gradle/wrapper/gradle-wrapper.jar.sha256 new file mode 100644 index 0000000..7e9c565 --- /dev/null +++ b/gradle/wrapper/gradle-wrapper.jar.sha256 @@ -0,0 +1 @@ +497c8c2a7e5031f6aa847f88104aa80a93532ec32ee17bdb8d1d2f67a194a9c7 diff --git a/pmd-rules.xml b/pmd-rules.xml index b5d8556..c8f7545 100644 --- a/pmd-rules.xml +++ b/pmd-rules.xml @@ -68,7 +68,6 @@ - diff --git a/sonar-project.properties b/sonar-project.properties index 8c6a9ef..f149fe0 100644 --- a/sonar-project.properties +++ b/sonar-project.properties @@ -1 +1,23 @@ -sonar.java.source=17 \ No newline at end of file +sonar.projectKey=toon-format_toon-java +sonar.organization=toon-format +sonar.host.url=https://sonarcloud.io + +sonar.projectName=JToon +sonar.projectDescription=Token-Oriented Object Notation (TOON) - A compact, human-readable format for LLM contexts +sonar.sourceEncoding=UTF-8 + +sonar.java.source=17 +sonar.java.target=17 +sonar.sources=src/main +sonar.tests=src/test +sonar.java.binaries=build/classes/java/main + +# Exclusions +sonar.exclusions=**/package-info.java + +# JaCoCo Coverage +sonar.coverage.jacoco.xmlReportPaths=build/customJacocoReportDir/test/jacocoTestReport.xml + +sonar.java.spotbugs.reportPaths=build/spotbugs/spotbugs-main.xml +sonar.java.pmd.reportPaths=build/reports/pmd/main.xml +sonar.java.checkstyle.reportPaths=build/reports/checkstyle/main.xml diff --git a/src/main/java/dev/toonformat/jtoon/decoder/KeyDecoder.java b/src/main/java/dev/toonformat/jtoon/decoder/KeyDecoder.java index 9229370..a1ad953 100644 --- a/src/main/java/dev/toonformat/jtoon/decoder/KeyDecoder.java +++ b/src/main/java/dev/toonformat/jtoon/decoder/KeyDecoder.java @@ -69,11 +69,9 @@ static void expandPathIntoMap(final Map current, final String do final Map nested = new LinkedHashMap<>(); currentMap.put(segment, nested); currentMap = nested; - } else if (existing instanceof Map) { - // Use existing nested object - @SuppressWarnings("unchecked") - final Map existingMap = (Map) existing; - currentMap = existingMap; + } else if (existing instanceof Map existingMap) { + // Use existing nested object; map was created as LinkedHashMap + currentMap = (Map) existingMap; } else { // Conflict: existing is not a Map if (context.options.strict()) {