diff --git a/src/applications/repository/query/PhabricatorRepositoryPushLogQuery.php b/src/applications/repository/query/PhabricatorRepositoryPushLogQuery.php
index cb097fae2f..d4734f61e6 100644
--- a/src/applications/repository/query/PhabricatorRepositoryPushLogQuery.php
+++ b/src/applications/repository/query/PhabricatorRepositoryPushLogQuery.php
@@ -1,159 +1,199 @@
 <?php
 
 final class PhabricatorRepositoryPushLogQuery
   extends PhabricatorCursorPagedPolicyAwareQuery {
 
   private $ids;
   private $phids;
   private $repositoryPHIDs;
   private $pusherPHIDs;
   private $refTypes;
   private $newRefs;
   private $pushEventPHIDs;
   private $epochMin;
   private $epochMax;
+  private $blockingHeraldRulePHIDs;
 
   public function withIDs(array $ids) {
     $this->ids = $ids;
     return $this;
   }
 
   public function withPHIDs(array $phids) {
     $this->phids = $phids;
     return $this;
   }
 
   public function withRepositoryPHIDs(array $repository_phids) {
     $this->repositoryPHIDs = $repository_phids;
     return $this;
   }
 
   public function withPusherPHIDs(array $pusher_phids) {
     $this->pusherPHIDs = $pusher_phids;
     return $this;
   }
 
   public function withRefTypes(array $ref_types) {
     $this->refTypes = $ref_types;
     return $this;
   }
 
   public function withNewRefs(array $new_refs) {
     $this->newRefs = $new_refs;
     return $this;
   }
 
   public function withPushEventPHIDs(array $phids) {
     $this->pushEventPHIDs = $phids;
     return $this;
   }
 
   public function withEpochBetween($min, $max) {
     $this->epochMin = $min;
     $this->epochMax = $max;
     return $this;
   }
 
+  public function withBlockingHeraldRulePHIDs(array $phids) {
+    $this->blockingHeraldRulePHIDs = $phids;
+    return $this;
+  }
+
   public function newResultObject() {
     return new PhabricatorRepositoryPushLog();
   }
 
   protected function loadPage() {
     return $this->loadStandardPage($this->newResultObject());
   }
 
   protected function willFilterPage(array $logs) {
     $event_phids = mpull($logs, 'getPushEventPHID');
     $events = id(new PhabricatorObjectQuery())
       ->setParentQuery($this)
       ->setViewer($this->getViewer())
       ->withPHIDs($event_phids)
       ->execute();
     $events = mpull($events, null, 'getPHID');
 
     foreach ($logs as $key => $log) {
       $event = idx($events, $log->getPushEventPHID());
       if (!$event) {
         unset($logs[$key]);
         continue;
       }
       $log->attachPushEvent($event);
     }
 
     return $logs;
   }
 
   protected function buildWhereClauseParts(AphrontDatabaseConnection $conn) {
     $where = parent::buildWhereClauseParts($conn);
 
     if ($this->ids !== null) {
       $where[] = qsprintf(
         $conn,
-        'id IN (%Ld)',
+        'log.id IN (%Ld)',
         $this->ids);
     }
 
     if ($this->phids !== null) {
       $where[] = qsprintf(
         $conn,
-        'phid IN (%Ls)',
+        'log.phid IN (%Ls)',
         $this->phids);
     }
 
     if ($this->repositoryPHIDs !== null) {
       $where[] = qsprintf(
         $conn,
-        'repositoryPHID IN (%Ls)',
+        'log.repositoryPHID IN (%Ls)',
         $this->repositoryPHIDs);
     }
 
     if ($this->pusherPHIDs !== null) {
       $where[] = qsprintf(
         $conn,
-        'pusherPHID in (%Ls)',
+        'log.pusherPHID in (%Ls)',
         $this->pusherPHIDs);
     }
 
     if ($this->pushEventPHIDs !== null) {
       $where[] = qsprintf(
         $conn,
-        'pushEventPHID in (%Ls)',
+        'log.pushEventPHID in (%Ls)',
         $this->pushEventPHIDs);
     }
 
     if ($this->refTypes !== null) {
       $where[] = qsprintf(
         $conn,
-        'refType IN (%Ls)',
+        'log.refType IN (%Ls)',
         $this->refTypes);
     }
 
     if ($this->newRefs !== null) {
       $where[] = qsprintf(
         $conn,
-        'refNew IN (%Ls)',
+        'log.refNew IN (%Ls)',
         $this->newRefs);
     }
 
     if ($this->epochMin !== null) {
       $where[] = qsprintf(
         $conn,
-        'epoch >= %d',
+        'log.epoch >= %d',
         $this->epochMin);
     }
 
     if ($this->epochMax !== null) {
       $where[] = qsprintf(
         $conn,
-        'epoch <= %d',
+        'log.epoch <= %d',
         $this->epochMax);
     }
 
+    if ($this->blockingHeraldRulePHIDs !== null) {
+      $where[] = qsprintf(
+        $conn,
+        '(event.rejectCode = %d AND event.rejectDetails IN (%Ls))',
+        PhabricatorRepositoryPushLog::REJECT_HERALD,
+        $this->blockingHeraldRulePHIDs);
+    }
+
     return $where;
   }
 
+  protected function buildJoinClauseParts(AphrontDatabaseConnection $conn) {
+    $joins = parent::buildJoinClauseParts($conn);
+
+    if ($this->shouldJoinPushEventTable()) {
+      $joins[] = qsprintf(
+        $conn,
+        'JOIN %T event ON event.phid = log.pushEventPHID',
+        id(new PhabricatorRepositoryPushEvent())->getTableName());
+    }
+
+    return $joins;
+  }
+
+  private function shouldJoinPushEventTable() {
+    if ($this->blockingHeraldRulePHIDs !== null) {
+      return true;
+    }
+
+    return false;
+  }
+
   public function getQueryApplicationClass() {
     return 'PhabricatorDiffusionApplication';
   }
 
+  protected function getPrimaryTableAlias() {
+    return 'log';
+  }
+
+
 }
diff --git a/src/applications/repository/query/PhabricatorRepositoryPushLogSearchEngine.php b/src/applications/repository/query/PhabricatorRepositoryPushLogSearchEngine.php
index eb2bc6b45b..87b2e44740 100644
--- a/src/applications/repository/query/PhabricatorRepositoryPushLogSearchEngine.php
+++ b/src/applications/repository/query/PhabricatorRepositoryPushLogSearchEngine.php
@@ -1,259 +1,269 @@
 <?php
 
 final class PhabricatorRepositoryPushLogSearchEngine
   extends PhabricatorApplicationSearchEngine {
 
   public function getResultTypeDescription() {
     return pht('Push Logs');
   }
 
   public function getApplicationClassName() {
     return 'PhabricatorDiffusionApplication';
   }
 
   public function newQuery() {
     return new PhabricatorRepositoryPushLogQuery();
   }
 
   protected function buildQueryFromParameters(array $map) {
     $query = $this->newQuery();
 
     if ($map['repositoryPHIDs']) {
       $query->withRepositoryPHIDs($map['repositoryPHIDs']);
     }
 
     if ($map['pusherPHIDs']) {
       $query->withPusherPHIDs($map['pusherPHIDs']);
     }
 
     if ($map['createdStart'] || $map['createdEnd']) {
       $query->withEpochBetween(
         $map['createdStart'],
         $map['createdEnd']);
     }
 
+    if ($map['blockingHeraldRulePHIDs']) {
+      $query->withBlockingHeraldRulePHIDs($map['blockingHeraldRulePHIDs']);
+    }
+
     return $query;
   }
 
   protected function buildCustomSearchFields() {
     return array(
       id(new PhabricatorSearchDatasourceField())
         ->setDatasource(new DiffusionRepositoryDatasource())
         ->setKey('repositoryPHIDs')
         ->setAliases(array('repository', 'repositories', 'repositoryPHID'))
         ->setLabel(pht('Repositories'))
         ->setDescription(
-          pht('Search for pull logs for specific repositories.')),
+          pht('Search for push logs for specific repositories.')),
       id(new PhabricatorUsersSearchField())
         ->setKey('pusherPHIDs')
         ->setAliases(array('pusher', 'pushers', 'pusherPHID'))
         ->setLabel(pht('Pushers'))
         ->setDescription(
-          pht('Search for pull logs by specific users.')),
+          pht('Search for push logs by specific users.')),
+      id(new PhabricatorSearchDatasourceField())
+        ->setDatasource(new HeraldRuleDatasource())
+        ->setKey('blockingHeraldRulePHIDs')
+        ->setLabel(pht('Blocked By'))
+        ->setDescription(
+          pht('Search for pushes blocked by particular Herald rules.')),
       id(new PhabricatorSearchDateField())
         ->setLabel(pht('Created After'))
         ->setKey('createdStart'),
       id(new PhabricatorSearchDateField())
         ->setLabel(pht('Created Before'))
         ->setKey('createdEnd'),
     );
   }
 
   protected function getURI($path) {
     return '/diffusion/pushlog/'.$path;
   }
 
   protected function getBuiltinQueryNames() {
     return array(
       'all' => pht('All Push Logs'),
     );
   }
 
   public function buildSavedQueryFromBuiltin($query_key) {
     $query = $this->newSavedQuery();
     $query->setQueryKey($query_key);
 
     switch ($query_key) {
       case 'all':
         return $query;
     }
 
     return parent::buildSavedQueryFromBuiltin($query_key);
   }
 
   protected function renderResultList(
     array $logs,
     PhabricatorSavedQuery $query,
     array $handles) {
 
     $table = id(new DiffusionPushLogListView())
       ->setViewer($this->requireViewer())
       ->setLogs($logs);
 
     return id(new PhabricatorApplicationSearchResultView())
       ->setTable($table);
   }
 
   protected function newExportFields() {
     $viewer = $this->requireViewer();
 
     $fields = array(
       id(new PhabricatorIDExportField())
         ->setKey('pushID')
         ->setLabel(pht('Push ID')),
       id(new PhabricatorStringExportField())
         ->setKey('unique')
         ->setLabel(pht('Unique')),
       id(new PhabricatorStringExportField())
         ->setKey('protocol')
         ->setLabel(pht('Protocol')),
       id(new PhabricatorPHIDExportField())
         ->setKey('repositoryPHID')
         ->setLabel(pht('Repository PHID')),
       id(new PhabricatorStringExportField())
         ->setKey('repository')
         ->setLabel(pht('Repository')),
       id(new PhabricatorPHIDExportField())
         ->setKey('pusherPHID')
         ->setLabel(pht('Pusher PHID')),
       id(new PhabricatorStringExportField())
         ->setKey('pusher')
         ->setLabel(pht('Pusher')),
       id(new PhabricatorPHIDExportField())
         ->setKey('devicePHID')
         ->setLabel(pht('Device PHID')),
       id(new PhabricatorStringExportField())
         ->setKey('device')
         ->setLabel(pht('Device')),
       id(new PhabricatorStringExportField())
         ->setKey('type')
         ->setLabel(pht('Ref Type')),
       id(new PhabricatorStringExportField())
         ->setKey('name')
         ->setLabel(pht('Ref Name')),
       id(new PhabricatorStringExportField())
         ->setKey('old')
         ->setLabel(pht('Ref Old')),
       id(new PhabricatorStringExportField())
         ->setKey('new')
         ->setLabel(pht('Ref New')),
       id(new PhabricatorIntExportField())
         ->setKey('flags')
         ->setLabel(pht('Flags')),
       id(new PhabricatorStringListExportField())
         ->setKey('flagNames')
         ->setLabel(pht('Flag Names')),
       id(new PhabricatorIntExportField())
         ->setKey('result')
         ->setLabel(pht('Result')),
       id(new PhabricatorStringExportField())
         ->setKey('resultName')
         ->setLabel(pht('Result Name')),
       id(new PhabricatorStringExportField())
         ->setKey('resultDetails')
         ->setLabel(pht('Result Details')),
       id(new PhabricatorIntExportField())
         ->setKey('writeWait')
         ->setLabel(pht('Write Wait (us)')),
       id(new PhabricatorIntExportField())
         ->setKey('readWait')
         ->setLabel(pht('Read Wait (us)')),
       id(new PhabricatorIntExportField())
         ->setKey('hostWait')
         ->setLabel(pht('Host Wait (us)')),
     );
 
     if ($viewer->getIsAdmin()) {
       $fields[] = id(new PhabricatorStringExportField())
         ->setKey('remoteAddress')
         ->setLabel(pht('Remote Address'));
     }
 
     return $fields;
   }
 
   protected function newExportData(array $logs) {
     $viewer = $this->requireViewer();
 
     $phids = array();
     foreach ($logs as $log) {
       $phids[] = $log->getPusherPHID();
       $phids[] = $log->getDevicePHID();
       $phids[] = $log->getPushEvent()->getRepositoryPHID();
     }
     $handles = $viewer->loadHandles($phids);
 
     $flag_map = PhabricatorRepositoryPushLog::getFlagDisplayNames();
     $reject_map = PhabricatorRepositoryPushLog::getRejectCodeDisplayNames();
 
     $export = array();
     foreach ($logs as $log) {
       $event = $log->getPushEvent();
 
       $repository_phid = $event->getRepositoryPHID();
       if ($repository_phid) {
         $repository_name = $handles[$repository_phid]->getName();
       } else {
         $repository_name = null;
       }
 
       $pusher_phid = $log->getPusherPHID();
       if ($pusher_phid) {
         $pusher_name = $handles[$pusher_phid]->getName();
       } else {
         $pusher_name = null;
       }
 
       $device_phid = $log->getDevicePHID();
       if ($device_phid) {
         $device_name = $handles[$device_phid]->getName();
       } else {
         $device_name = null;
       }
 
       $flags = $log->getChangeFlags();
       $flag_names = array();
       foreach ($flag_map as $flag_key => $flag_name) {
         if (($flags & $flag_key) === $flag_key) {
           $flag_names[] = $flag_name;
         }
       }
 
       $result = $event->getRejectCode();
       $result_name = idx($reject_map, $result, pht('Unknown ("%s")', $result));
 
       $map = array(
         'pushID' => $event->getID(),
         'unique' => $event->getRequestIdentifier(),
         'protocol' => $event->getRemoteProtocol(),
         'repositoryPHID' => $repository_phid,
         'repository' => $repository_name,
         'pusherPHID' => $pusher_phid,
         'pusher' => $pusher_name,
         'devicePHID' => $device_phid,
         'device' => $device_name,
         'type' => $log->getRefType(),
         'name' => $log->getRefName(),
         'old' => $log->getRefOld(),
         'new' => $log->getRefNew(),
         'flags' => $flags,
         'flagNames' => $flag_names,
         'result' => $result,
         'resultName' => $result_name,
         'resultDetails' => $event->getRejectDetails(),
         'writeWait' => $event->getWriteWait(),
         'readWait' => $event->getReadWait(),
         'hostWait' => $event->getHostWait(),
       );
 
       if ($viewer->getIsAdmin()) {
         $map['remoteAddress'] = $event->getRemoteAddress();
       }
 
       $export[] = $map;
     }
 
     return $export;
   }
 
 }
diff --git a/src/applications/repository/storage/PhabricatorRepositoryPushEvent.php b/src/applications/repository/storage/PhabricatorRepositoryPushEvent.php
index e44f99df4d..682b367926 100644
--- a/src/applications/repository/storage/PhabricatorRepositoryPushEvent.php
+++ b/src/applications/repository/storage/PhabricatorRepositoryPushEvent.php
@@ -1,103 +1,106 @@
 <?php
 
 /**
  * Groups a set of push logs corresponding to changes which were all pushed in
  * the same transaction.
  */
 final class PhabricatorRepositoryPushEvent
   extends PhabricatorRepositoryDAO
   implements PhabricatorPolicyInterface {
 
   protected $repositoryPHID;
   protected $epoch;
   protected $pusherPHID;
   protected $requestIdentifier;
   protected $remoteAddress;
   protected $remoteProtocol;
   protected $rejectCode;
   protected $rejectDetails;
   protected $writeWait;
   protected $readWait;
   protected $hostWait;
 
   private $repository = self::ATTACHABLE;
   private $logs = self::ATTACHABLE;
 
   public static function initializeNewEvent(PhabricatorUser $viewer) {
     return id(new PhabricatorRepositoryPushEvent())
       ->setPusherPHID($viewer->getPHID());
   }
 
   protected function getConfiguration() {
     return array(
       self::CONFIG_AUX_PHID => true,
       self::CONFIG_TIMESTAMPS => false,
       self::CONFIG_COLUMN_SCHEMA => array(
         'requestIdentifier' => 'bytes12?',
         'remoteAddress' => 'ipaddress?',
         'remoteProtocol' => 'text32?',
         'rejectCode' => 'uint32',
         'rejectDetails' => 'text64?',
         'writeWait' => 'uint64?',
         'readWait' => 'uint64?',
         'hostWait' => 'uint64?',
       ),
       self::CONFIG_KEY_SCHEMA => array(
         'key_repository' => array(
           'columns' => array('repositoryPHID'),
         ),
         'key_identifier' => array(
           'columns' => array('requestIdentifier'),
         ),
+        'key_reject' => array(
+          'columns' => array('rejectCode', 'rejectDetails'),
+        ),
       ),
     ) + parent::getConfiguration();
   }
 
   public function generatePHID() {
     return PhabricatorPHID::generateNewPHID(
       PhabricatorRepositoryPushEventPHIDType::TYPECONST);
   }
 
   public function attachRepository(PhabricatorRepository $repository) {
     $this->repository = $repository;
     return $this;
   }
 
   public function getRepository() {
     return $this->assertAttached($this->repository);
   }
 
   public function attachLogs(array $logs) {
     $this->logs = $logs;
     return $this;
   }
 
   public function getLogs() {
     return $this->assertAttached($this->logs);
   }
 
 
 /* -(  PhabricatorPolicyInterface  )----------------------------------------- */
 
 
   public function getCapabilities() {
     return array(
       PhabricatorPolicyCapability::CAN_VIEW,
     );
   }
 
   public function getPolicy($capability) {
     return $this->getRepository()->getPolicy($capability);
   }
 
   public function hasAutomaticCapability($capability, PhabricatorUser $viewer) {
     return $this->getRepository()->hasAutomaticCapability($capability, $viewer);
   }
 
   public function describeAutomaticCapability($capability) {
     return pht(
       "A repository's push events are visible to users who can see the ".
       "repository.");
   }
 
 }