Translate

2017年4月10日月曜日

Hubot Document: Patterns を翻訳して、チャットボットでありがちな実装を確認する

Hubot Document: Scripting
https://hubot.github.com/docs/scripting/
を読めばHubot上で動作するチャットボットの書き方がわかるとおもい
前回の記事で翻訳してみた。

が、よくあるパターンサンプル集もあるとうれしい..

ということで
Hubot Documentation: Patterns
https://hubot.github.com/docs/patterns/
も引き続き翻訳してみた。



参照する場合は at your own risk でお願いします。
----------

Hubot Documentation: Patterns




一般的な Hubot 活用シナリオを扱うためのパターンを共有します。

Hubot インスタンスのリネーム


Hubot の名前を変更すると、元の名前に反応しなくなります。 ユーザに新しい名前を慣れさせるために、古い名前への発言に非推奨通知を追加することを選択できます。 パターンロジックは次のとおりです;

  • 古い名前で始まるすべてのメッセージをlisten
  • ユーザにreplyして、新しい名前について知らせる

この設定はとても簡単です:

  1. Hubot インスタンスの scripts/ ディレクトリに rename-hubot.coffee という バンドルされたスクリプトを作成
  2. 必要に応じて変更された次のコードを追加:
# Description:
#   Tell people hubot's new name if they use the old one
#
# Commands:
#   None
#
module.exports = (robot) ->
  robot.hear /^hubot:? (.+)/i, (res) ->
    response = "Sorry, I'm a diva and only respond to #{robot.name}"
    response += " or #{robot.alias}" if robot.alias
    res.reply response
    return


上記のパターンでは、ニーズに合わせて hubot リスナと応答メッセージの両方を変更します。

また、リスナは Hubot アダプタが処理する前にチャットプログラムに入力されたものではなく、実際に聞こえるものに基づいている必要があることに注意することが重要です。 たとえば、"HipChat アダプタ" は @hubothubot: に変換してから Hubot に渡します。


非推奨リスナまたは改名されたリスナ


スクリプトを削除したり、スクリプトのコマンドを変更した際に、変更内容をユーザに知らせることができます。 1つの方法は、チャットでそれらを伝えること、またはもはや存在しないコマンドを使用することによって変更を検出させることです。 別の方法は、Hubot に動作しないコマンドを使用したときに知らせることです。

このパターンは、上記の Hubot インスタンスパターンの名前変更に似ています:

  • 古いコマンドと一致するすべてのメッセージをlisten
  • ユーザに reply して、そのユーザが非推奨になったことを知らせる

セットアップ方法はこちら:

  1. deprecations.coffee という Hubot インスタンスの scripts/ ディレクトリにバンドルされたスクリプトを作成します
  2. 古いコマンドリスナをコピして、そのファイルに追加します。たとえば、何らかの理由で help コマンドの名前を変更する場合は、次のようにします:
# Description:
#   Tell users when they have used commands that are deprecated or renamed
#
# Commands:
#   None
#
module.exports = (robot) ->
  robot.respond /help\s*(.*)?$/i, (res) ->
    res.reply "That means nothing to me anymore. Perhaps you meant `docs` instead?"
    return


Proxy経由による HTTPリスエストのフォワーディング


多くの企業環境では、インターネットおよび/または保護されたリソースにアクセスするためにWeb Proxy が必要です。 一回限りの制御の場合、 robot.http で使用する "Agent" を指定できます。 しかし、これでは、ロボットが Proxy を指すために使用するすべてのスクリプトを変更する必要があります。 代わりに、グローバルレベルでAgentを指定し、デフォルトですべてのHTTP要求にAgentを使用させることができます。

node.jsによるHTTP要求とHTTPS要求に対する処理方法のために、プロトコルごとに異なるAgentを指定する必要があります。 ScopedHTTPClient は自動的に、各要求に対して正しい ProxyAgent を選択します。

  1. ProxyAgent をインストールします npm install proxy-agent
    Hubotインスタンス上の scripts/ ディレクトリに proxy.coffee と呼ばれる バンドルスクリプト を作成します
  2. 必要に応じて変更された次のコードを追加します:
proxy = require 'proxy-agent'
module.exports = (robot) ->
  robot.globalHttpOptions.httpAgent  = proxy('http://my-proxy-server.internal', false)
  robot.globalHttpOptions.httpsAgent = proxy('http://my-proxy-server.internal', true)


メッセージの動的マッチング


状況によっては、異なるメッセージ(例えば、factoids、JIRAプロジェクトなど)を動的に一致させたい場合があります。 常に一致する広範な正規表現を定義するのではなく、特定の条件が満たされたときだけ Hubot に一致するように指示することができます。

シンプルなロボットでは、これはListenerコールバックに条件を入れることとあまり変わりませんが、ミドルウェアを扱うときに大きな違いがあります。基本モデルでは、汎用正規表現の一致ごとにミドルウェアが実行されます 。 動的整合モデルでは、動的条件が一致した場合にのみミドルウェアが実行されます。

例えば、factoids ルックアップコマンドは次のように再実装できます:
module.exports = (robot) ->
  # Dynamically populated list of factoids
  facts =
    fact1: 'stuff'
    fact2: 'other stuff'

  robot.listen(
    # Matcher
    (message) ->
      match = message.match(/^~(.*)$/)
      # Only match if there is a matching factoid
      if match and match[1] in facts
        match[1]
      else
        false
    # Callback
    (response) ->
      fact = response.match
      res.reply "#{fact} is #{facts[fact]}"
  )



コマンドへのアクセス制限


Hubot のすばらしい機能の1つは、単一のチャットメッセージを使用して本番環境に変更を加える能力です。 ただし、チャットサービスにアクセスできる人は誰もが、プロダクションの変更を引き起こすことはできません。

特定のニーズに応じてアクセスを制限するさまざまなパターンがあります:

  • アクセスの2つのバケット:フルリストとホワイトリスト/ブラックリストで制限付き
  • すべてのコマンド(ロールベースのアクセス制御)に対する特定のアクセスルール
  • 特定の部屋のブラックリスト/ホワイトリストのコマンド

単純なリスナごとのアクセス


一部の組織では、ほぼすべての従業員に同じレベルのアクセス権が与えられており、限られた少数のユーザ(たとえば、新規採用者、請負業者など)のみが制限されています。 このモデルでは、すべてのリスナのセットを分割して、「通常のコマンド」から「パワーコマンド」を分離します。

リスナを分離したら、ホワイトリスト/ブラックリストのユーザとリスナの間でいくつかのトレードオフの決定をする必要があります。

ホワイトリスト作成とブラックリスト登録の重要な決定要素は、各カテゴリのユーザ数、どちらのカテゴリの変更頻度、組織が受け入れるセキュリティリスクのレベルです。

  • ユーザをホワイトリストに登録すると(ユーザX、Y、Zはパワーコマンドにアクセスでき、他のすべてのユーザは通常のコマンドにのみアクセスできます)、より安全なアクセス方法です(新しいユーザはパワーコマンドにデフォルトでアクセスできません) 新しい各ユーザを「承認済み」リストに追加する必要があります)。
  • ユーザをブラックリストに登録すると(ブラックリストに追加されるまで、新しいユーザは電源コマンドにデフォルトでアクセスできます)、ユーザをブラックリストに登録する(すべてのユーザは電源コマンドにアクセスできますが、通常のコマンドにしかアクセスできないユーザX、Y、Zは除きます) ブラックリストが小規模/めったに更新されていない場合はメンテナンスオーバーヘッドが大幅に低くなります。

リスナを選択的に許可するかどうかを決定する重要な要因は、各カテゴリのリスナ数、内部スクリプトと外部スクリプトの比率、組織が受け入れるセキュリティリスクのレベルです。

  • すべてのリスナは通常のコマンドと見なされるリスナA、B、Cを除いてすべてのリスナを選択的に許可しますが、新しいリスナはデフォルトで制限されています (おバカな/遊びのためのリスナは明示的に「通常」の状態にダウングレードする必要があります)。
  • リスナを選択的に制限する(リスナA、B、Cはパワーコマンドですが、それ以外のコマンドはすべて通常のコマンドです)、セキュリティ保護されていない方法です(新しいリスナはデフォルトで通常のカテゴリに入れられます 。保守オーバヘッドは低くなります(アクセスポリシのすべての遊びのための/文化的なスクリプトを変更/列挙する必要はありません)。

追加の考慮事項として、ほとんどのスクリプトは現在リスナIDを持っていないので、リスナIDを追加するために使用する外部スクリプトをPR(またはfork)する必要があります。 実際の変更は簡単ですが、多くのメンテナと調整することは時間がかかることがあります。

可能な4つのモデルのうちどれを選択するかを決めたら、承認ミドルウェアに接続するための適切なユーザとリスナのリストを作成する必要があります。

例:選択的に制限されたパワーコマンドにアクセスできるユーザのホワイトリスト
POWER_COMMANDS = [
  'deploy.web' # String that matches the listener ID
]

POWER_USERS = [
  'jdoe' # String that matches the user ID set by the adapter
]

module.exports = (robot) ->
  robot.listenerMiddleware (context, next, done) ->
    if context.listener.options.id in POWER_COMMANDS
      if context.response.message.user.id in POWER_USERS
        # User is allowed access to this command
        next()
      else
        # Restricted command, but user isn't in whitelist
        context.response.reply "I'm sorry, @#{context.response.message.user.name}, but you don't have access to do that."
        done()
    else
      # This is not a restricted command; allow everyone
      next()

ミドルウェアは、特定のメッセージ( robot.hear /.+/ を含む) に一致するすべてのリスナに対して実行されるので、リスナを分類するときにそれらを含めるようにしてください。


リスナごとの特定のアクセスルール


大規模な組織では、通常、アクセスのバイナリ分類が不十分で、より複雑なアクセスルールが必要です。

アクセスポリシの例:

  • 各開発チームは、リリースをカットしてサービスを展開することができます
  • Operations グループは、すべてのサービスを展開するためのアクセス権を持っています(ただし、カットリリースではありません)
  • フロントデスクはリリースをカットしたり、サービスを展開することはできません

このような複雑なポリシは現在、コードで直接実装するのが最善ですが、アクセス管理のための一般化されたフレームワークを構築するための "継続的な作業" があります。


ルームごとの特定のアクセスルール


さまざまな目的を果たす多数のチャットルームを持つ組織では、同一の hubot インスタンスを使用できるようにすることがしばしばですが、各ルームで異なるコマンドセットを使用できます。

一般化されたブラックリストソリューションに関する作業が 進行中 です。 ホワイトリストのソリューションも同様のアプローチをとることができます。

以上
----------

想像していたのは、もっとアプリアプリしてるサンプルコードだったのだけど..

Proxy経由でのアクセス方法があったから、
まあ
よしとしようか..



0 件のコメント:

既存アプリケーションをK8s上でコンテナ化して動かす場合の設計注意事項メモ

既存アプリをK8sなどのコンテナにして動かすには、どこを注意すればいいか..ちょっと調べたときの注意事項をメモにした。   1. The Twelve Factors (日本語訳からの転記) コードベース   バージョン管理されている1つのコードベースと複数のデプロイ 依存関係 ...