@@ -394,5 +394,185 @@ private module FabricV2 {
394394 )
395395 }
396396 }
397+
398+ // -------------------------------------------------------------------------
399+ // fabric.group
400+ // -------------------------------------------------------------------------
401+ /** Gets a reference to the `fabric.group` module. */
402+ DataFlow:: Node group ( ) { result = fabric_attr ( "group" ) }
403+
404+ /** Provides models for the `fabric.group` module */
405+ module group {
406+ /**
407+ * Gets a reference to the attribute `attr_name` of the `fabric.group` module.
408+ * WARNING: Only holds for a few predefined attributes.
409+ */
410+ private DataFlow:: Node group_attr ( DataFlow:: TypeTracker t , string attr_name ) {
411+ attr_name in [ "SerialGroup" , "ThreadingGroup" ] and
412+ (
413+ t .start ( ) and
414+ result = DataFlow:: importNode ( "fabric.group" + "." + attr_name )
415+ or
416+ t .startInAttr ( attr_name ) and
417+ result = group ( )
418+ )
419+ or
420+ // Due to bad performance when using normal setup with `group_attr(t2, attr_name).track(t2, t)`
421+ // we have inlined that code and forced a join
422+ exists ( DataFlow:: TypeTracker t2 |
423+ exists ( DataFlow:: StepSummary summary |
424+ group_attr_first_join ( t2 , attr_name , result , summary ) and
425+ t = t2 .append ( summary )
426+ )
427+ )
428+ }
429+
430+ pragma [ nomagic]
431+ private predicate group_attr_first_join (
432+ DataFlow:: TypeTracker t2 , string attr_name , DataFlow:: Node res ,
433+ DataFlow:: StepSummary summary
434+ ) {
435+ DataFlow:: StepSummary:: step ( group_attr ( t2 , attr_name ) , res , summary )
436+ }
437+
438+ /**
439+ * Gets a reference to the attribute `attr_name` of the `fabric.group` module.
440+ * WARNING: Only holds for a few predefined attributes.
441+ */
442+ private DataFlow:: Node group_attr ( string attr_name ) {
443+ result = group_attr ( DataFlow:: TypeTracker:: end ( ) , attr_name )
444+ }
445+
446+ /**
447+ * Provides models for the `fabric.group.Group` class and its subclasses.
448+ *
449+ * `fabric.group.Group` is an abstract class, that has concrete implementations
450+ * `SerialGroup` and `ThreadingGroup`.
451+ *
452+ * See
453+ * - https://docs.fabfile.org/en/2.5/api/group.html#fabric.group.Group
454+ * - https://docs.fabfile.org/en/2.5/api/group.html#fabric.group.SerialGroup
455+ * - https://docs.fabfile.org/en/2.5/api/group.html#fabric.group.ThreadingGroup
456+ */
457+ module Group {
458+ /**
459+ * A source of an instance of a subclass of `fabric.group.Group`
460+ *
461+ * This can include instantiation of a class, return value from function
462+ * calls, or a special parameter that will be set when functions are call by external
463+ * library.
464+ *
465+ * Use `Group::subclassInstance()` predicate to get references to an instance of a subclass of `fabric.group.Group`.
466+ */
467+ abstract class SubclassInstanceSource extends DataFlow:: Node { }
468+
469+ /** Gets a reference to an instance of a subclass of `fabric.group.Group`. */
470+ private DataFlow:: Node subclassInstance ( DataFlow:: TypeTracker t ) {
471+ t .start ( ) and
472+ result instanceof SubclassInstanceSource
473+ or
474+ exists ( DataFlow:: TypeTracker t2 | result = subclassInstance ( t2 ) .track ( t2 , t ) )
475+ }
476+
477+ /** Gets a reference to an instance of a subclass of `fabric.group.Group`. */
478+ DataFlow:: Node subclassInstance ( ) {
479+ result = subclassInstance ( DataFlow:: TypeTracker:: end ( ) )
480+ }
481+
482+ /**
483+ * Gets a reference to the `run` method on an instance of a subclass of `fabric.group.Group`.
484+ *
485+ * See https://docs.fabfile.org/en/2.5/api/group.html#fabric.group.Group.run
486+ */
487+ private DataFlow:: Node subclassInstanceRunMethod ( DataFlow:: TypeTracker t ) {
488+ t .startInAttr ( "run" ) and
489+ result = subclassInstance ( )
490+ or
491+ exists ( DataFlow:: TypeTracker t2 | result = subclassInstanceRunMethod ( t2 ) .track ( t2 , t ) )
492+ }
493+
494+ /**
495+ * Gets a reference to the `run` method on an instance of a subclass of `fabric.group.Group`.
496+ *
497+ * See https://docs.fabfile.org/en/2.5/api/group.html#fabric.group.Group.run
498+ */
499+ DataFlow:: Node subclassInstanceRunMethod ( ) {
500+ result = subclassInstanceRunMethod ( DataFlow:: TypeTracker:: end ( ) )
501+ }
502+ }
503+
504+ /**
505+ * A call to `run`, `sudo` on an instance of a subclass of `fabric.group.Group`.
506+ *
507+ * See https://docs.fabfile.org/en/2.5/api/group.html#fabric.group.Group.run
508+ */
509+ private class FabricGroupRunCall extends SystemCommandExecution:: Range , DataFlow:: CfgNode {
510+ override CallNode node ;
511+
512+ FabricGroupRunCall ( ) {
513+ node .getFunction ( ) = fabric:: group:: Group:: subclassInstanceRunMethod ( ) .asCfgNode ( )
514+ }
515+
516+ override DataFlow:: Node getCommand ( ) {
517+ result .asCfgNode ( ) = [ node .getArg ( 0 ) , node .getArgByName ( "command" ) ]
518+ }
519+ }
520+
521+ /**
522+ * Provides models for the `fabric.group.SerialGroup` class
523+ *
524+ * See https://docs.fabfile.org/en/2.5/api/group.html#fabric.group.SerialGroup.
525+ */
526+ module SerialGroup {
527+ /** Gets a reference to the `fabric.group.SerialGroup` class. */
528+ private DataFlow:: Node classRef ( DataFlow:: TypeTracker t ) {
529+ t .start ( ) and
530+ result = group_attr ( "SerialGroup" )
531+ or
532+ // Handle `fabric.SerialGroup` alias
533+ t .start ( ) and
534+ result = fabric_attr ( "SerialGroup" )
535+ or
536+ exists ( DataFlow:: TypeTracker t2 | result = classRef ( t2 ) .track ( t2 , t ) )
537+ }
538+
539+ /** Gets a reference to the `fabric.group.SerialGroup` class. */
540+ private DataFlow:: Node classRef ( ) { result = classRef ( DataFlow:: TypeTracker:: end ( ) ) }
541+
542+ private class ClassInstantiation extends Group:: SubclassInstanceSource , DataFlow:: CfgNode {
543+ override CallNode node ;
544+
545+ ClassInstantiation ( ) { node .getFunction ( ) = classRef ( ) .asCfgNode ( ) }
546+ }
547+ }
548+
549+ /**
550+ * Provides models for the `fabric.group.ThreadingGroup` class
551+ *
552+ * See https://docs.fabfile.org/en/2.5/api/group.html#fabric.group.ThreadingGroup.
553+ */
554+ module ThreadingGroup {
555+ /** Gets a reference to the `fabric.group.ThreadingGroup` class. */
556+ private DataFlow:: Node classRef ( DataFlow:: TypeTracker t ) {
557+ t .start ( ) and
558+ result = group_attr ( "ThreadingGroup" )
559+ or
560+ // Handle `fabric.ThreadingGroup` alias
561+ t .start ( ) and
562+ result = fabric_attr ( "ThreadingGroup" )
563+ or
564+ exists ( DataFlow:: TypeTracker t2 | result = classRef ( t2 ) .track ( t2 , t ) )
565+ }
566+
567+ /** Gets a reference to the `fabric.group.ThreadingGroup` class. */
568+ DataFlow:: Node classRef ( ) { result = classRef ( DataFlow:: TypeTracker:: end ( ) ) }
569+
570+ private class ClassInstantiation extends Group:: SubclassInstanceSource , DataFlow:: CfgNode {
571+ override CallNode node ;
572+
573+ ClassInstantiation ( ) { node .getFunction ( ) = classRef ( ) .asCfgNode ( ) }
574+ }
575+ }
576+ }
397577 }
398578}
0 commit comments