gnodet-bot commented on code in PR #28099:
URL: https://github.com/apache/camel/pull/28099#discussion_r4312627897


##########
components/camel-pqc/src/main/java/org/apache/camel/component/pqc/PQCProducer.java:
##########
@@ -1146,47 +1155,67 @@ private void checkStatefulKeyBeforeSign() {
     }
 
     /**
-     * Persists stateful key state after a signing operation through the 
KeyLifecycleManager, if configured. This
-     * ensures the key index is tracked across restarts.
+     * Records the use of the signing key through the KeyLifecycleManager, if 
one is configured and the exchange names a
+     * key.
+     * <p/>
+     * This advances {@code usageCount}, which is what the {@code maxKeyUsage} 
rotation signal of
+     * {@link org.apache.camel.component.pqc.lifecycle.KeyRotationScheduler} 
reads. It must therefore run for every key,
+     * not only the stateful ones: ML-DSA, SLH-DSA, Falcon and the KEM keys 
would otherwise sit at a usage count of zero
+     * forever and never be rotated.
+     * <p/>
+     * For a stateful signature key the advanced private key is stored as 
well, so the one-time index survives a
+     * restart.
      */
-    private void persistStatefulKeyStateAfterSign(Exchange exchange) throws 
Exception {
+    private void recordKeyUsageAfterSign(Exchange exchange) throws Exception {
         if (keyPair == null || keyPair.getPrivate() == null) {
             return;
         }
 
         PrivateKey privateKey = keyPair.getPrivate();
-        long remaining = getStatefulKeyRemaining(privateKey);
-        if (remaining < 0) {
-            // Not a stateful key
-            return;
-        }
+        boolean stateful = getStatefulKeyRemaining(privateKey) >= 0;
 
         KeyLifecycleManager klm = getConfiguration().getKeyLifecycleManager();
         if (klm == null) {
+            warnStatefulStateNotPersisted(stateful, "no keyLifecycleManager is 
configured on the endpoint");
             return;
         }
 
         String keyId = exchange.getMessage().getHeader(PQCConstants.KEY_ID, 
String.class);
         if (ObjectHelper.isEmpty(keyId)) {
+            warnStatefulStateNotPersisted(stateful,
+                    "the exchange carries no " + PQCConstants.KEY_ID + " 
header identifying the key");
             return;
         }
 
-        // Update metadata with current usage
         KeyMetadata metadata = klm.getKeyMetadata(keyId);
         if (metadata == null) {
-            LOG.warn(
-                    "No metadata found for stateful key '{}'. The key index 
has been advanced by the signing operation "
-                     + "but cannot be persisted — on restart this index 
advance will be lost, which may lead to key reuse. "
-                     + "Ensure a KeyLifecycleManager is properly configured 
and the key is stored with metadata.",
-                    keyId);
+            warnStatefulStateNotPersisted(stateful, "the keyLifecycleManager 
holds no metadata for key '" + keyId + "'");
             return;
         }
 
         metadata.updateLastUsed();

Review Comment:
   ⚠️ **Non-stateful keys silently skip `updateLastUsed()` / 
`updateKeyMetadata()` when a prerequisite is missing**
   
   The Javadoc just added states:
   > *It must therefore run for every key, not only the stateful ones: ML-DSA, 
SLH-DSA, Falcon and the KEM keys would otherwise sit at a usage count of zero 
forever and never be rotated.*
   
   However, the three early-return guards (`klm == null`, `keyId` empty, 
`metadata == null`) exit before `metadata.updateLastUsed()` / 
`klm.updateKeyMetadata()` are reached. When `stateful == false`, 
`warnStatefulStateNotPersisted` is a no-op (the `compareAndSet` guard is gated 
on `stateful`), so the skip is entirely silent. Non-stateful keys (ML-DSA, 
SLH-DSA, Falcon, KEM) will have their `usageCount` stuck at zero and will never 
be rotated by `KeyRotationScheduler` if any of these conditions apply.
   
   Consider separating the two concerns: if `klm` is `null` (or `keyId` is 
missing, or `metadata` is absent), a non-stateful key should still have its 
`usageCount` incremented in-memory — only the stateful persist-to-store path 
actually requires those prerequisites.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to