EQL: Deprecate lenient sequence declaration (#55032)

Deprecate alternative sequence parameter declaration (with then by)
Disallow lack of time units inside maxspan

Fix #55023
Relate #54680

(cherry picked from commit 201adafba9def1de4bf843760defb9def3394f63)
This commit is contained in:
Costin Leau 2020-04-10 10:29:17 +03:00 committed by Costin Leau
parent bf0cadb602
commit a7e4f79e8f
5 changed files with 55 additions and 44 deletions

View File

@ -30,7 +30,7 @@ sequenceParams
; ;
sequence sequence
: SEQUENCE (by=joinKeys sequenceParams? | sequenceParams by=joinKeys?)? : SEQUENCE (by=joinKeys sequenceParams? | sequenceParams disallowed=joinKeys?)?
sequenceTerm sequenceTerm+ sequenceTerm sequenceTerm+
(UNTIL until=sequenceTerm)? (UNTIL until=sequenceTerm)?
; ;

View File

@ -393,6 +393,7 @@ class EqlBaseParser extends Parser {
public static class SequenceContext extends ParserRuleContext { public static class SequenceContext extends ParserRuleContext {
public JoinKeysContext by; public JoinKeysContext by;
public JoinKeysContext disallowed;
public SequenceTermContext until; public SequenceTermContext until;
public TerminalNode SEQUENCE() { return getToken(EqlBaseParser.SEQUENCE, 0); } public TerminalNode SEQUENCE() { return getToken(EqlBaseParser.SEQUENCE, 0); }
public List<SequenceTermContext> sequenceTerm() { public List<SequenceTermContext> sequenceTerm() {
@ -462,7 +463,7 @@ class EqlBaseParser extends Parser {
if (_la==BY) { if (_la==BY) {
{ {
setState(83); setState(83);
((SequenceContext)_localctx).by = joinKeys(); ((SequenceContext)_localctx).disallowed = joinKeys();
} }
} }

View File

@ -112,8 +112,13 @@ public abstract class LogicalPlanBuilder extends ExpressionBuilder {
@Override @Override
public Sequence visitSequence(SequenceContext ctx) { public Sequence visitSequence(SequenceContext ctx) {
List<Expression> parentJoinKeys = visitJoinKeys(ctx.by); Source source = source(ctx);
if (ctx.disallowed != null && ctx.sequenceParams() != null) {
throw new ParsingException(source, "Please specify sequence [by] before [with] not after");
}
List<Expression> parentJoinKeys = visitJoinKeys(ctx.by);
TimeValue maxSpan = visitSequenceParams(ctx.sequenceParams()); TimeValue maxSpan = visitSequenceParams(ctx.sequenceParams());
LogicalPlan until; LogicalPlan until;
@ -122,7 +127,7 @@ public abstract class LogicalPlanBuilder extends ExpressionBuilder {
until = visitSequenceTerm(ctx.until, parentJoinKeys); until = visitSequenceTerm(ctx.until, parentJoinKeys);
} else { } else {
// no until declared means the condition never gets executed and thus folds to false // no until declared means the condition never gets executed and thus folds to false
until = new Filter(source(ctx), RELATION, new Literal(source(ctx), Boolean.FALSE, DataTypes.BOOLEAN)); until = new Filter(source, RELATION, new Literal(source(ctx), Boolean.FALSE, DataTypes.BOOLEAN));
} }
int numberOfKeys = -1; int numberOfKeys = -1;
@ -145,7 +150,7 @@ public abstract class LogicalPlanBuilder extends ExpressionBuilder {
} }
} }
return new Sequence(source(ctx), queries, until, maxSpan); return new Sequence(source, queries, until, maxSpan);
} }
public KeyedFilter visitSequenceTerm(SequenceTermContext ctx, List<Expression> joinKeys) { public KeyedFilter visitSequenceTerm(SequenceTermContext ctx, List<Expression> joinKeys) {
@ -173,45 +178,40 @@ public abstract class LogicalPlanBuilder extends ExpressionBuilder {
} }
String timeString = text(ctx.timeUnit().IDENTIFIER()); String timeString = text(ctx.timeUnit().IDENTIFIER());
TimeUnit timeUnit = TimeUnit.SECONDS;
if (timeString != null) { if (timeString == null) {
throw new ParsingException(source(ctx.timeUnit()), "No time unit specified, did you mean [s] as in [{}s]?", text(ctx
.timeUnit()));
}
TimeUnit timeUnit = null;
switch (timeString) { switch (timeString) {
case "": case "ms":
timeUnit = TimeUnit.MILLISECONDS;
break;
case "s": case "s":
case "sec":
case "secs":
case "second":
case "seconds":
timeUnit = TimeUnit.SECONDS; timeUnit = TimeUnit.SECONDS;
break; break;
case "m": case "m":
case "min":
case "mins":
case "minute":
case "minutes":
timeUnit = TimeUnit.MINUTES; timeUnit = TimeUnit.MINUTES;
break; break;
case "h": case "h":
case "hs":
case "hour":
case "hours":
timeUnit = TimeUnit.HOURS; timeUnit = TimeUnit.HOURS;
break; break;
case "d": case "d":
case "ds":
case "day":
case "days":
timeUnit = TimeUnit.DAYS; timeUnit = TimeUnit.DAYS;
break; break;
default: default:
throw new ParsingException(source(ctx.timeUnit().IDENTIFIER()), "Unrecognized time unit [{}]", timeString); throw new ParsingException(source(ctx.timeUnit().IDENTIFIER()),
} "Unrecognized time unit [{}] in [{}], please specify one of [ms, s, m, h, d]",
timeString, text(ctx.timeUnit()));
} }
return new TimeValue(value, timeUnit); return new TimeValue(value, timeUnit);
} else { } else {
throw new ParsingException(source(numberCtx), "Decimal time interval [{}] not supported yet", text(numberCtx)); throw new ParsingException(source(numberCtx), "Decimal time interval [{}] not supported; please use an positive integer",
text(numberCtx));
} }
} }
} }

View File

@ -20,9 +20,9 @@ public class QueryFolderFailTests extends AbstractQueryFolderTestCase {
} }
private String errorParsing(String eql) { private String errorParsing(String eql) {
ParsingException e = expectThrows(ParsingException.class, () -> plan(eql)); Exception e = expectThrows(Exception.class, () -> plan(eql));
assertTrue(e.getClass().getSimpleName().endsWith("ParsingException"));
final String header = "line "; final String header = "line ";
assertTrue(e.getMessage().startsWith(header));
return e.getMessage().substring(header.length()); return e.getMessage().substring(header.length());
} }
@ -187,4 +187,14 @@ public class QueryFolderFailTests extends AbstractQueryFolderTestCase {
assertEquals("Found 1 problem\n" + assertEquals("Found 1 problem\n" +
"line 1:15: first argument of [wildcard(pid, '*.exe')] must be [string], found value [pid] type [long]", msg); "line 1:15: first argument of [wildcard(pid, '*.exe')] must be [string], found value [pid] type [long]", msg);
} }
public void testSequenceWithBeforeBy() {
String msg = errorParsing("sequence with maxspan=1s by key [a where true] [b where true]");
assertEquals("1:2: Please specify sequence [by] before [with] not after", msg);
}
public void testSequenceWithNoTimeUnit() {
String msg = errorParsing("sequence with maxspan=30 [a where true] [b where true]");
assertEquals("1:24: No time unit specified, did you mean [s] as in [30s]?", msg);
}
} }

View File

@ -546,7 +546,7 @@ sequence by unique_pid
[network where true] [network where true]
; ;
sequence by pid with maxspan=200 sequence by pid with maxspan=200s
[process where process_name == "*" ] [process where process_name == "*" ]
[file where file_path == "*"] [file where file_path == "*"]
; ;
@ -556,12 +556,12 @@ sequence by pid with maxspan=2s
[file where file_path == "*"] [file where file_path == "*"]
; ;
sequence by pid with maxspan=2sec sequence by pid with maxspan=500ms
[process where process_name == "*" ] [process where process_name == "*" ]
[file where file_path == "*"] [file where file_path == "*"]
; ;
sequence by pid with maxspan=2seconds sequence by pid with maxspan=2h
[process where process_name == "*" ] [process where process_name == "*" ]
[file where file_path == "*"] [file where file_path == "*"]
; ;