Skip to content

Commit d139b1f

Browse files
authored
Merge pull request #523 from hjotha/submit/skip-system-java-actions-validation
fix: skip System.* references in `mxcli check --references`
2 parents fcbe2b0 + a123e74 commit d139b1f

2 files changed

Lines changed: 110 additions & 0 deletions

File tree

mdl/executor/validate.go

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,14 @@ func validateFlowBodyReferences(ctx *ExecContext, body []ast.MicroflowStatement,
478478
if len(refs.javaActions) > 0 {
479479
known := buildJavaActionQualifiedNames(ctx)
480480
for _, ref := range refs.javaActions {
481+
// System.* Java actions (e.g. System.VerifyPassword,
482+
// System.GenerateRandomString) are runtime-provided and never
483+
// appear in the project's MPR. Skip them to avoid false
484+
// positives — Studio Pro's `mx check` resolves these against
485+
// the runtime, which `mxcli check` cannot reach.
486+
if isBuiltinModuleEntity(qualifiedNameModule(ref)) {
487+
continue
488+
}
481489
if !known[ref] {
482490
errors = append(errors, fmt.Sprintf("java action not found: %s (referenced by call java action)", ref))
483491
}
@@ -487,6 +495,9 @@ func validateFlowBodyReferences(ctx *ExecContext, body []ast.MicroflowStatement,
487495
if len(refs.javaScriptActions) > 0 {
488496
known := buildJavaScriptActionQualifiedNames(ctx)
489497
for _, ref := range refs.javaScriptActions {
498+
if isBuiltinModuleEntity(qualifiedNameModule(ref)) {
499+
continue
500+
}
490501
if !known[ref] {
491502
errors = append(errors, fmt.Sprintf("javascript action not found: %s (referenced by call javascript action)", ref))
492503
}
@@ -505,6 +516,15 @@ func validateFlowBodyReferences(ctx *ExecContext, body []ast.MicroflowStatement,
505516
return errors
506517
}
507518

519+
// qualifiedNameModule returns the module portion of a "Module.Name" qualified
520+
// name. It returns an empty string when the input has no dot.
521+
func qualifiedNameModule(qn string) string {
522+
if i := strings.Index(qn, "."); i >= 0 {
523+
return qn[:i]
524+
}
525+
return ""
526+
}
527+
508528
// flowRefCollector collects qualified name references from flow body statements.
509529
type flowRefCollector struct {
510530
pages []string
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
// SPDX-License-Identifier: Apache-2.0
2+
3+
package executor
4+
5+
import (
6+
"strings"
7+
"testing"
8+
9+
"github.com/mendixlabs/mxcli/mdl/ast"
10+
"github.com/mendixlabs/mxcli/mdl/backend/mock"
11+
"github.com/mendixlabs/mxcli/model"
12+
"github.com/mendixlabs/mxcli/sdk/javaactions"
13+
"github.com/mendixlabs/mxcli/sdk/microflows"
14+
)
15+
16+
// `mxcli check --references` must not flag System.* Java actions
17+
// (System.VerifyPassword, System.GenerateRandomString, etc.) as missing.
18+
// They are runtime-provided and never appear in the project MPR; flagging
19+
// them produces false positives on any microflow that uses Mendix
20+
// built-ins, including the Administration module's password flows.
21+
func TestValidateMicroflowReferencesSkipsSystemJavaAction(t *testing.T) {
22+
moduleID := model.ID("module-1")
23+
backend := &mock.MockBackend{
24+
IsConnectedFunc: func() bool { return true },
25+
ListModulesFunc: func() ([]*model.Module, error) {
26+
return []*model.Module{{
27+
BaseElement: model.BaseElement{ID: moduleID},
28+
Name: "Administration",
29+
}}, nil
30+
},
31+
ListMicroflowsFunc: func() ([]*microflows.Microflow, error) {
32+
return nil, nil
33+
},
34+
ListJavaActionsFunc: nil,
35+
}
36+
ctx, _ := newMockCtx(t, withBackend(backend))
37+
38+
stmt := &ast.CreateMicroflowStmt{
39+
Name: ast.QualifiedName{Module: "Administration", Name: "ChangeMyPassword"},
40+
Body: []ast.MicroflowStatement{
41+
&ast.CallJavaActionStmt{
42+
ActionName: ast.QualifiedName{Module: "System", Name: "VerifyPassword"},
43+
},
44+
},
45+
}
46+
47+
if err := validate(ctx, stmt); err != nil {
48+
t.Fatalf("System.* Java action reference must not error, got: %v", err)
49+
}
50+
}
51+
52+
// User-module Java action references are still validated. A missing one
53+
// must error out so genuine typos don't slip through.
54+
func TestValidateMicroflowReferencesReportsMissingUserJavaAction(t *testing.T) {
55+
moduleID := model.ID("module-1")
56+
backend := &mock.MockBackend{
57+
IsConnectedFunc: func() bool { return true },
58+
ListModulesFunc: func() ([]*model.Module, error) {
59+
return []*model.Module{{
60+
BaseElement: model.BaseElement{ID: moduleID},
61+
Name: "Administration",
62+
}}, nil
63+
},
64+
ListMicroflowsFunc: func() ([]*microflows.Microflow, error) {
65+
return nil, nil
66+
},
67+
ListJavaActionsFunc: nil,
68+
ReadJavaActionByNameFunc: func(qn string) (*javaactions.JavaAction, error) {
69+
return nil, nil
70+
},
71+
}
72+
ctx, _ := newMockCtx(t, withBackend(backend))
73+
74+
stmt := &ast.CreateMicroflowStmt{
75+
Name: ast.QualifiedName{Module: "Administration", Name: "BadCall"},
76+
Body: []ast.MicroflowStatement{
77+
&ast.CallJavaActionStmt{
78+
ActionName: ast.QualifiedName{Module: "Administration", Name: "NonExistentJavaAction"},
79+
},
80+
},
81+
}
82+
83+
err := validate(ctx, stmt)
84+
if err == nil {
85+
t.Fatal("expected missing user Java action reference error")
86+
}
87+
if !strings.Contains(err.Error(), "java action not found: Administration.NonExistentJavaAction") {
88+
t.Fatalf("unexpected error: %v", err)
89+
}
90+
}

0 commit comments

Comments
 (0)