mattcasters commented on code in PR #8825:
URL: https://github.com/apache/hop/pull/8825#discussion_r4231976231


##########
plugins/misc/lint/src/main/java/org/apache/hop/lint/CustomRuleExecutor.java:
##########
@@ -433,9 +441,18 @@ private static Object extractFieldValue(Object hopObject, 
String fieldName, Cust
             return dbMeta.getUsername();
           case "password":
             return dbMeta.getPassword();
+          case "servername":
+            return dbMeta.getServername();
+          case "dataTablespace":
+            return dbMeta.getDataTablespace();
+          case "indexTablespace":
+            return dbMeta.getIndexTablespace();
+          case "attributes":
+            // The extra options are attributes too, stored as 
EXTRA_OPTION_<type>.<option>.
+            return dbMeta.getAttributes();
           default:
-            log.logDetailed("Unknown database field: " + fieldName);
-            return null;
+            // Any other connection property, such as manualUrl, by getter or 
field.
+            return extractFieldFromObject(dbMeta, fieldName);

Review Comment:
   **[bug]** The new default calls `extractFieldFromObject`, so a rule on 
`sshTunnelPassphrase` invokes `DatabaseMeta.getSshTunnelPassphrase()`. That 
property is `@HopMetadataProperty(password = true)` on the nested database 
interface, but `storedAsPassword` only looks for a field of that name on 
`DatabaseMeta` itself, and `holdsASecret` only matches names that end with 
`password`, `secret`, `token`, and the other existing suffixes. `passphrase` 
matches none of them, so `generateErrorMessage` appends the stored secret as 
`(current value: ...)`. `sshTunnelPassword` stays hidden only because of the 
`password` suffix. Attribute maps are redacted; this string is not. A 
`NO_HARDCODED` rule, which is the rule someone would write for this field, is 
exactly the case that prints it. That is the CI-log leak DB-001 was closed to 
stop, on a getter this fallback newly exposes.
   
   **Suggestion:** When the object is a `DatabaseMeta`, also resolve `password 
= true` on `getIDatabase()`. Treat a name ending in `passphrase` as a secret. 
Add a test that a finding for `sshTunnelPassphrase` does not contain the value.



##########
plugins/misc/lint/src/main/java/org/apache/hop/lint/CustomRuleExecutor.java:
##########
@@ -586,6 +619,26 @@ private static Object extractFieldFromAction(ActionMeta 
actionMeta, String field
           return actionMeta.getDescription();
         case "pluginId":
           return actionMeta.getAction().getPluginId();
+        case "errorHandling":
+          // An action handles its errors with a hop followed on failure.
+          return SUBJECT.get() instanceof WorkflowMeta workflow
+              ? workflow.getWorkflowHops().stream()
+                  .anyMatch(
+                      hop ->
+                          hop.isEnabled()
+                              && actionMeta.equals(hop.getFromAction())
+                              && !hop.isUnconditional()
+                              && !hop.isEvaluation())
+              : null;
+        case "targetActions":
+          return SUBJECT.get() instanceof WorkflowMeta workflow
+              ? workflow.getWorkflowHops().stream()
+                  .filter(hop -> hop.isEnabled() && 
actionMeta.equals(hop.getFromAction()))
+                  .map(hop -> hop.getToAction().getName())

Review Comment:
   **[bug]** `hop.getToAction().getName()` throws when the hop's target was not 
resolved. `WorkflowHopMeta` still keeps that hop, with `to == null`. The same 
try also calls `actionMeta.equals(hop.getFromAction())` for `errorHandling` and 
for this filter. `ActionMeta.equals` returns false for a null argument, but it 
dereferences `action.getName()` on both sides when the argument is non-null, so 
a from-action whose inner `IAction` is null throws too. The catch returns null 
for the entire `targetActions` list and for `errorHandling`. A 
`NOT_EMPTY_COLLECTION` or `MUST_BE_TRUE` rule then passes, including for the 
hops that were fine.
   
   **Suggestion:** Keep a hop only when both ends are non-null, and compare 
those ends without going through `ActionMeta.equals` unless the inner action is 
present. Build the list from the hops that resolved instead of failing the 
whole field.



##########
plugins/misc/lint/src/main/java/org/apache/hop/lint/CustomRuleExecutor.java:
##########
@@ -548,6 +571,16 @@ private static Object extractFieldFromTransform(
         case "copies":
           return transformMeta.getCopies(
               
org.apache.hop.core.variables.Variables.getADefaultVariableSpace());
+        case "distributes":
+          return transformMeta.isDistributes();
+        case "errorHandling":
+          return transformMeta.getTransform() != null && 
transformMeta.isDoingErrorHandling();
+        case "targetTransforms":
+          return SUBJECT.get() instanceof PipelineMeta pipeline
+              ? pipeline.findNextTransforms(transformMeta).stream()
+                  .map(TransformMeta::getName)

Review Comment:
   **[bug]** `PipelineMeta.findNextTransforms` puts a hop's `to` transform in 
the list even when that reference is null. A saved hop whose target name no 
longer matches a transform is loaded that way (`PipelineHopMeta` keeps the 
hop). `TransformMeta::getName` then throws. A null `from` throws inside 
`findNextTransforms` itself (`getFromTransform().equals(...)`). Either 
exception is caught below, logged at detailed level, and turned into null for 
the whole field. Null is not `FIELD_NOT_FOUND`: `NOT_EMPTY_COLLECTION` and 
`MAX_COLLECTION_SIZE` return false, so the rule passes and every other target 
on that transform is dropped. One broken hop blanks `targetTransforms` for 
every transform, because `findNextTransforms` walks every hop before it returns.
   
   **Suggestion:** Do not call `findNextTransforms` unchecked. Walk enabled 
hops, skip those with a null from or to, and map only the names that resolved. 
An extraction failure should not become a null that the presence checks treat 
as success.



##########
plugins/misc/lint/src/main/java/org/apache/hop/lint/CustomRuleExecutor.java:
##########
@@ -433,9 +441,18 @@ private static Object extractFieldValue(Object hopObject, 
String fieldName, Cust
             return dbMeta.getUsername();
           case "password":
             return dbMeta.getPassword();
+          case "servername":
+            return dbMeta.getServername();
+          case "dataTablespace":
+            return dbMeta.getDataTablespace();
+          case "indexTablespace":
+            return dbMeta.getIndexTablespace();
+          case "attributes":
+            // The extra options are attributes too, stored as 
EXTRA_OPTION_<type>.<option>.
+            return dbMeta.getAttributes();
           default:
-            log.logDetailed("Unknown database field: " + fieldName);
-            return null;
+            // Any other connection property, such as manualUrl, by getter or 
field.

Review Comment:
   **[suggestion]** `extractFieldFromObject` tries `getX` and a method whose 
name is the field, not `isX`. Connection flags are `isSshTunnelEnabled`, 
`isQuoteAllFields`, `isStreamingResults`, and so on, so they come back as 
`FIELD_NOT_FOUND`. This change reports every unresolved connection field as an 
error, so a rule on `sshTunnelEnabled` says the field does not exist on every 
connection, even though the getter is there. `manualUrl` works only because it 
is `getManualUrl`.
   
   **Suggestion:** Before returning `FIELD_NOT_FOUND`, also try `is` plus the 
capitalized name. Otherwise the new "any other connection property" path and 
the "missing connection field is always an error" path disagree for booleans.



-- 
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