Skip to content

Release Java SDK v17.2.1#975

Open
stas-schaller wants to merge 7 commits into
masterfrom
release/sdk/java/core/v17.2.1
Open

Release Java SDK v17.2.1#975
stas-schaller wants to merge 7 commits into
masterfrom
release/sdk/java/core/v17.2.1

Conversation

@stas-schaller
Copy link
Copy Markdown
Contributor

@stas-schaller stas-schaller commented Mar 23, 2026

Summary

Release branch for Java SDK v17.2.1 — three changes: IL5 region support, serialization correctness for record create, and file attachment crash fix.

Changes

New Features

  • IL5 region mapping (KSM-902): added \"IL5\" -> \"il5.keepersecurity.us\" to the initializeStorage() region map in SecretsManager.kt. Tokens prefixed IL5: now route to the DoD Impact Level 5 environment.

Bug Fixes

  • Custom field omitted from record create payload (KSM-823): KeeperRecordData.custom defaulted to null, causing kotlinx-serialization to omit \"custom\" from the V3 API payload when no custom fields were set. Changed default to mutableListOf() and added @EncodeDefault to force inclusion. Regression test added.
  • KeeperFileData crash when lastModified absent (KSM-854): files uploaded by non-SDK clients (iOS, Android, Web Vault) omit lastModified; kotlinx-serialization treated it as required, throwing MissingFieldException and silently dropping the attachment. Added = 0 default, consistent with .NET SDK behavior (KSM-674).

Deferred to v17.2.2

  • Resource leaks in LocalConfigStorage and SecretsManager (KSM-855): deferred to v17.2.2 for faster v17.2.1 QA cycle. Full implementation available in feature branch feature/java-ksm-855-resource-leaks.

Breaking Changes

None.

Related Issues

@stas-schaller stas-schaller force-pushed the release/sdk/java/core/v17.2.1 branch from e5e9bc7 to 1802c4c Compare March 27, 2026 18:31
@stas-schaller stas-schaller force-pushed the release/sdk/java/core/v17.2.1 branch from 1802c4c to b1f61c1 Compare April 9, 2026 19:38
@stas-schaller stas-schaller changed the title feat(sdk/java): release Java SDK v17.2.1 Release Java SDK v17.2.1 Apr 14, 2026
@stas-schaller stas-schaller marked this pull request as ready for review April 15, 2026 21:20
Comment thread .github/workflows/reusable.maven.central.publish.yml Fixed
## Bug Fixes
- KSM-854: fix KeeperFileData crash when lastModified is absent
- KSM-823: always include custom:[] in record create payload
- KSM-855: fix resource leaks in LocalConfigStorage and SecretsManager

## Features
- KSM-902: add IL5 region mapping (il5.keepersecurity.us)

## CI/CD
- Replace Syft with CycloneDX Gradle plugin (org.cyclonedx.bom v3.2.4) for accurate
  Maven purl generation (correct groupIds like org.jetbrains.kotlin vs kotlin-reflect)
- Scope SBOM to runtimeClasspath only — excludes test deps and Kotlin compiler internals
- Set SBOM root componentName to keeper-secrets-manager-java
- Switch Manifest SBOM upload to manifest-cyber/manifest-github-action@v1.6.0
  (pre-generated BOM file upload, no Syft invocation)
- Add build-only mode to publish workflow (publish boolean input, default true)
- Gate Maven Central publish via confirm-publish dependency cascade — preserves
  environment: prod release manager approval without firing on build-only runs
- SHA-pin all actions (gradle/actions, ksm-action, manifest-cyber action, checkout,
  setup-java, upload-artifact) and upgrade to Node.js 24 compatible versions
- Fix template injection findings — move needs outputs to env vars in verify step
- Add path filter to test.java.yml (sdk/java/core/**)
- Remove EOL Java 16/18 from test matrix; add Java 21 LTS
@stas-schaller stas-schaller force-pushed the release/sdk/java/core/v17.2.1 branch from 636ee8c to 1edd61a Compare April 20, 2026 20:10
Three complementary layers so IL5 customers can supply key ID 20
without it being embedded in the shipped SDK:

- Layer 1 (config field): if `serverPublicKey` is present in storage
  (e.g. populated from a base64 config JSON), `generateTransmissionKey`
  uses those bytes instead of the embedded table.

- Layer 2 (extended OTT): `initializeStorage` now parses a 4-segment
  token `REGION:clientKey:keyId:serverPublicKey`, saving both
  `serverPublicKeyId` and `serverPublicKey` to storage on bind.

- Layer 3 (constructor param): `SecretsManagerOptions` accepts an
  optional `serverPublicKey` string that is immediately persisted to
  storage, so the key is available for all subsequent requests.

Adds `KEY_SERVER_PUBLIC_KEY` constant. Existing behaviour is unchanged
when the field is absent; the embedded key table is still used for all
commercial environments.
KSM-902: Java IL5 dynamic server public key support
Copy link
Copy Markdown

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

⚠️ Code review skipped — your organization has reached its monthly code review spending cap.

An organization admin can view or raise the cap at claude.ai/admin-settings/claude-code. The cap resets at the start of the next billing period.

Once the cap resets or is raised, push a new commit or reopen this pull request to trigger a review.

- Add serverPublicKeyId parameter to SecretsManagerOptions (Layer 3
  parity with serverPublicKey); both params persist to storage on init
- Validate 4-segment OTT: require exactly 4 parts, keyId must be a
  positive integer, serverPublicKey must be >= 80 chars
- Gate key-rotation overwrite in postQuery: when a custom server public
  key is configured, a rotation hint throws a clear error instead of
  silently replacing the custom key ID
- Rename KEY_SERVER_PUBIC_KEY_ID (typo) to KEY_SERVER_PUBLIC_KEY_ID
  across SecretsManager.kt, LocalConfigStorage.kt, and tests; constant
  introduced in this release branch so no published API is broken
- Replace fake testIL5ConfigFieldOverridesEmbeddedTable with a test
  that actually calls generateTransmissionKey via getSecrets and
  verifies key ID 999 (not in embedded table) reaches the post function
Workflow fixes:
- Remove max-parallel: 1 from test.java.yml — no reason to serialize the JVM matrix
- Add validate-version gate: fails fast if the version is already on Maven Central
- Add standalone test job that runs in parallel with SBOM generation; tests no
  longer run inside publish-to-maven-central (removed redundant ./gradlew clean build test)
- Fix base64 -w 0 in Bearer token construction — Linux base64 line-wraps at 76
  chars without this flag, silently producing a malformed auth header
- Anchor version grep to line start (^version) so a future multi-version
  build.gradle.kts cannot match the wrong assignment

RecordData.kt:
- Add @jvmoverloads to KeeperFileData constructor for Java caller ergonomics
- Add inline comments explaining @EncodeDefault (KSM-823), FlexibleLongSerializer
  (KSM-673), and lastModified default of 0 (KSM-854)
Copy link
Copy Markdown

@claude claude Bot left a comment

Choose a reason for hiding this comment

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

⚠️ Code review skipped — your organization has reached its monthly code review spending cap.

An organization admin can view or raise the cap at claude.ai/admin-settings/claude-code. The cap resets at the start of the next billing period.

Once the cap resets or is raised, push a new commit or reopen this pull request to trigger a review.

Comment on lines +88 to +109
needs: validate-version
runs-on: ubuntu-latest
defaults:
run:
working-directory: ${{ inputs.working-directory }}

steps:
- name: Checkout repository
uses: actions/checkout@v4

- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false
- name: Set up Java ${{ inputs.java-version }}
uses: actions/setup-java@v4
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
with:
java-version: ${{ inputs.java-version }}
distribution: 'temurin'

- name: Setup Gradle
uses: gradle/actions/setup-gradle@v4

- name: Build project and copy dependencies
run: |
echo "Building project to resolve dependencies..."
./gradlew build -x test --no-daemon --refresh-dependencies
uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0
with:
gradle-version: '8.14'
- name: Build and Test
run: ./gradlew clean build --no-daemon

echo "Copying runtime dependencies for SBOM scanning..."
./gradlew copyDependencies
generate-and-upload-sbom:
Comment on lines +110 to +153
needs: [get-version, validate-version]
runs-on: ubuntu-latest
defaults:
run:
working-directory: ${{ inputs.working-directory }}

echo "Dependencies collected:"
ls -la build/sbom-deps/ || echo "Warning: sbom-deps directory not created"
steps:
- name: Checkout repository
uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
with:
persist-credentials: false

echo "Excluding fatJar from SBOM (test artifact only):"
find build/libs -name "*.jar" -type f ! -name "*-fat.jar" || true
- name: Set up Java ${{ inputs.java-version }}
uses: actions/setup-java@be666c2fcd27ec809703dec50e508c2fdc7f6654 # v5.2.0
with:
java-version: ${{ inputs.java-version }}
distribution: 'temurin'

- name: Install SBOM tools
run: |
echo "Installing Syft v1.18.1..."
curl -sSfL https://raw.githubusercontent.com/anchore/syft/main/install.sh | sh -s -- -b /usr/local/bin v1.18.1
- name: Setup Gradle
uses: gradle/actions/setup-gradle@50e97c2cd7a37755bbfafc9c5b7cafaece252f6e # v6.1.0

echo "Installing Manifest CLI v0.18.3..."
curl -sSfL https://raw.githubusercontent.com/manifest-cyber/cli/main/install.sh | sh -s -- -b . v0.18.3
chmod +x ./manifest
- name: Build project
run: ./gradlew build -x test --no-daemon

echo "Verifying installations..."
syft version
./manifest --version
- name: Generate SBOM with CycloneDX
run: ./gradlew cyclonedxBom --no-daemon

- name: Generate and publish SBOM
env:
MANIFEST_TOKEN: ${{ secrets.MANIFEST_TOKEN }}
run: |
echo "Creating Syft configuration for Java/Kotlin scanning..."
cat > syft-config.yaml << 'EOF'
package:
search:
scope: all-layers
unindexed-archives: true
indexed-archives: true
cataloger:
enabled: true
java:
enabled: true
search-unindexed-archives: true
search-indexed-archives: true
resolve-dependencies: true
use-network: false
max-parent-recursive-depth: 10
# Disable non-Java catalogers
ruby:
enabled: false
python:
enabled: false
nodejs:
enabled: false
dotnet:
enabled: false
golang:
enabled: false
EOF

echo "Generating SBOM with Manifest CLI..."
./manifest sbom build/sbom-deps \
--generator=syft \
--generator-config=syft-config.yaml \
--name=${{ inputs.project-name }} \
--version=${{ needs.get-version.outputs.version }} \
--output=spdx-json \
--file=sbom.json \
--api-key=${MANIFEST_TOKEN} \
--publish=true \
--asset-label=application,sbom-generated,java,sdk,maven,security
- name: Publish SBOM to Manifest
uses: manifest-cyber/manifest-github-action@a90e8d22cb1a607317ec76cc9c53f61769c06213 # v1.6.0
with:
apiKey: ${{ secrets.MANIFEST_TOKEN }}
bomFilePath: ${{ inputs.working-directory }}/build/reports/cyclonedx/bom.json
sbomName: ${{ inputs.project-name }}
sbomVersion: ${{ needs.get-version.outputs.version }}
asset-labels: application,sbom-generated,java,sdk,maven,security

- name: Archive SBOM
uses: actions/upload-artifact@v4
uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7
with:
name: sbom-${{ inputs.project-name }}-${{ needs.get-version.outputs.version }}
path: ${{ inputs.working-directory }}/sbom.json
retention-days: 90
name: sbom-cyclonedx-${{ inputs.project-name }}-${{ needs.get-version.outputs.version }}
path: ${{ inputs.working-directory }}/build/reports/cyclonedx/bom.json
retention-days: 10

confirm-publish:
Comment thread .github/workflows/reusable.maven.central.publish.yml Fixed
@socket-security
Copy link
Copy Markdown

socket-security Bot commented May 20, 2026

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updatedmaven/​com.google.guava/​guava@​33.4.6-jre ⏵ 33.1.0-jre36 +610090100100
Updatedmaven/​org.junit.jupiter/​junit-jupiter@​5.12.1 ⏵ 5.10.21001009010070

View full report

Add if: inputs.publish == true to publish-to-maven-central so GitHub
does not create a pending deployment entry for environment: prod when
the job will be skipped. Without this, build-only runs show a spurious
waiting-to-publish indicator in the PR and Deployments UI.
Comment on lines 161 to 344
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Keeper Java/Kotlin: Field 'lastModified' is required for type with serial name...

2 participants