rules:
  - id: possible-mutable-default-args
    pattern-either:
      - pattern: |
          def $FUNC(..., $ARG = $FUNC2(...), ...):
            ...
      - pattern: |
          def $FUNC(..., $ARG = $FUNC2(...).$ATTR, ...):
            ...
      - pattern: |
          def $FUNC(..., $ARG = jingrow.$ATTR, ...):
            ...

    message: |
      `$ARG` is possibly a mutable default argument. May not work as expected during subsequent calls of `$FUNC` without $ARG.
    languages:
      - python
    severity: WARNING
    metadata:
      category: correctness
      technology:
        - python
      references:
        - https://docs.python-guide.org/writing/gotchas/#mutable-default-arguments

  - id: except-with-db-code
    languages:
      - python
    patterns:
      - pattern-inside: |
          try:
            ...
          except ...:
            $ERR_HANDL_BLK
      - pattern-either:
          - pattern: |
              try:
                ...
              except ...:
                ...
                $DOC.save(...)
                ...
                raise
                ...
          - pattern: |
              try:
                ...
              except ...:
                ...
                jingrow. ... .set_value(...)
                ...
                raise
                ...
          - pattern: |
              try:
                ...
              except ...:
                ...
                $DOC.db_set(...)
                ...
                raise
                ...
      - pattern-not: |
          try:
            ...
          except ...:
            ...
            $DOC.save(...)
            ...
            jingrow.db.commit(...)
            raise
          ...
      - pattern-not: |
          try:
            ...
          except ...:
            ...
            jingrow. ... .set_value(...)
            ...
            jingrow.db.commit(...)
            raise
            ...
      - pattern-not: |
          try:
            ...
          except ...:
            ...
            $DOC.db_set(...)
            ...
            jingrow.db.commit(...)
            ...
            raise
            ...
      - focus-metavariable: $ERR_HANDL_BLK

    message: except block has no db commit before raise. The db changes made won't persist assuming innodb tables.
    severity: ERROR

  - id: retries-without-until
    languages:
      - yaml
    patterns:
      - pattern: |
          ...
          retries: $RETRIES
          delay: $DELAY
          ...

      - pattern-not: |
          ...
          retries: $RETRIES
          delay: $DELAY
          until: $UNTIL
          ...

    paths:
      include:
        - 'jcloud/playbooks/**/*.yml'
    message: retry block doesn't have until condition. Only works with ansible 2.16 and above.
    severity: ERROR
    metadata:
      category: correctness
      references:
        - https://docs.ansible.com/ansible/latest/playbook_guide/playbooks_loops.html#retrying-a-task-until-a-condition-is-met
        - https://docs.ansible.com/ansible/latest/reference_appendices/release_and_maintenance.html#ansible-community-changelogs

  - id: nginx-update-called-in-loop
    languages:
      - python
    patterns:
      - pattern-inside: |
          for $VAR in $LIST:
            ...
      - pattern-either:
          - pattern: Site(...).unsuspend(...)
          - pattern: Site(...).suspend(...)
          - pattern: Site(...).activate(...)
          - pattern: Site(...).deactivate(...)
          - pattern: $OBJ.get_pg("Site", ...).unsuspend(...)
          - pattern: $OBJ.get_pg("Site", ...).suspend(...)
          - pattern: $OBJ.get_pg("Site", ...).activate(...)
          - pattern: $OBJ.get_pg("Site", ...).deactivate(...)
          - pattern: $OBJ.get_last_pg("Site", ...).unsuspend(...)
          - pattern: $OBJ.get_last_pg("Site", ...).suspend(...)
          - pattern: $OBJ.get_last_pg("Site", ...).activate(...)
          - pattern: $OBJ.get_last_pg("Site", ...).deactivate(...)
          - pattern: $OBJ.update_site_status_on_proxy(...)
          - pattern: $OBJ.update_site_status(...)
          - pattern: deactivate_site_on_source_proxy(...)
          - pattern: activate_site_on_destination_proxy(...)

      - pattern-not: Site(...).unsuspend(..., skip_reload=True, ...)
      - pattern-not: Site(...).suspend(..., skip_reload=True, ...)
      - pattern-not: Site(...).activate(..., skip_reload=True, ...)
      - pattern-not: Site(...).deactivate(..., skip_reload=True, ...)
      - pattern-not: $OBJ.get_pg("Site", ...).unsuspend(..., skip_reload=True, ...)
      - pattern-not: $OBJ.get_pg("Site", ...).suspend(..., skip_reload=True, ...)
      - pattern-not: $OBJ.get_pg("Site", ...).activate(..., skip_reload=True, ...)
      - pattern-not: $OBJ.get_pg("Site", ...).deactivate(..., skip_reload=True, ...)
      - pattern-not: $OBJ.get_last_pg("Site", ...).unsuspend(..., skip_reload=True, ...)
      - pattern-not: $OBJ.get_last_pg("Site", ...).suspend(..., skip_reload=True, ...)
      - pattern-not: $OBJ.get_last_pg("Site", ...).activate(..., skip_reload=True, ...)
      - pattern-not: $OBJ.get_last_pg("Site", ...).deactivate(..., skip_reload=True, ...)
      - pattern-not: $OBJ.update_site_status_on_proxy(..., skip_reload=True, ...)
      - pattern-not: $OBJ.update_site_status(..., skip_reload=True, ...)

    message: Agent endpoint that updates nginx is called in a loop. This causes nginx to reload configuration multiple times which takes proxy down.
    severity: ERROR
    metadata:
      references:
        - https://www.f5.com/ko_kr/company/blog/nginx/using-nginx-plus-to-reduce-the-frequency-of-configuration-reloads
