Web サイトの診断ツール Sonar のCLIを使ってみる


Web サイトの診断ツール Sonar を使ってみる | Monotalk に続いて、sonar, a linting tool for the web の Cli ツールを使ってみます。


目次


CLI ツールを実行する

User guide | sonar documentation を参考にインストール、ツールを実行します。

インストール、作業ディレクトリの作成

  • インストール
    % npm install -g --engine-strict @sonarwhal/sonar
    
  • OUTPUT

    /usr/local/bin/sonar -> /usr/local/lib/node_modules/@sonarwhal/sonar/dist/src/bin/sonar.js
    
    > canvas-prebuilt@1.6.0 install /usr/local/lib/node_modules/@sonarwhal/sonar/node_modules/canvas-prebuilt
    > node-pre-gyp install
    
    [canvas-prebuilt] Success: "/usr/local/lib/node_modules/@sonarwhal/sonar/node_modules/canvas-prebuilt/canvas/build/Release/canvas-prebuilt.node" is installed via remote
    
    > amphtml-validator@1.0.20 postinstall /usr/local/lib/node_modules/@sonarwhal/sonar/node_modules/amphtml-validator
    > /bin/sh -c "exit 0" 2> postinstall.DELETEME && rm postinstall.DELETEME || node postinstall-windows.js
    
    
    > axe-core@2.4.2 postinstall /usr/local/lib/node_modules/@sonarwhal/sonar/node_modules/axe-core
    > node build/utils/postinstall.js
    
    + @sonarwhal/sonar@0.13.0
    added 438 packages in 81.745s
    

  • 作業ディレクトリを作成
    init コマンドを打つため、作業ディレクトリを作成します。

    mkdir sonar
    

init コマンド実行

  • ディレクトリ移動、initコマンドを実行
    cd sonar
    sonar --init
    

以下、console 上で幾つか質問を聞かれるので、答えていきます。

  • ブラウザを選択
    chrome を選択しました。

    Welcome to sonar configuration generator
    ? What connector do you want to use? (Use arrow keys)
    ❯ chrome 
      jsdom 
    

  • formatter を選択
    json を選択しました。

    ? What formatter do you want to use? 
    ❯ codeframe 
      json 
      stylish 
      summary 
    

  • 推奨ルールを使うか否かを選択
    Y を選択しました。

    ? Do you want to use the recommended rules configuration? 
    

  • 対象ブラウザを選択
    Default を選択しました。

    ? What browsers are you targeting? (Use arrow keys)
    ❯ Default (last 2 versions of each browser, and browsers with globaly usage over 1%, plus Firefox ESR) 
      Custom (use browserslist format:  https://github.com/ai/browserslist#queries) 
    

  • .sonarrc の内容を確認
    選択した設定に従い、.sonarrc が作成されます。
    上記の選択だと、以下の内容で作成されました。

    % cat .sonarrc 
    {
        "browserslist": [],
        "connector": {
            "name": "chrome",
            "options": {
                "waitFor": 1000
            }
        },
        "formatters": [
            "json"
        ],
        "ignoredUrls": [],
        "rules": {
            "amp-validator": "off",
            "apple-touch-icons": "error",
            "axe": "error",
            "content-type": "error",
            "disown-opener": "error",
            "highest-available-document-mode": "error",
            "html-checker": "error",
            "image-optimization-cloudinary": "off",
            "manifest-app-name": "error",
            "manifest-exists": "error",
            "manifest-file-extension": "error",
            "manifest-is-valid": "error",
            "meta-charset-utf-8": "error",
            "meta-viewport": "error",
            "no-disallowed-headers": "error",
            "no-friendly-error-pages": "error",
            "no-html-only-headers": "error",
            "no-protocol-relative-urls": "error",
            "no-vulnerable-javascript-libraries": "error",
            "ssllabs": "off",
            "strict-transport-security": "error",
            "validate-set-cookie-header": "error",
            "x-content-type-options": "error"
        },
        "rulesTimeout": 120000
    }
    

チェック実行

このサイトに対して、チェックを実行します。

  • チェック実行

    sonar https://www.monotalk.xyz
    

  • 警告の抜粋
    json フォーマットを選択したので、json形式で出力されます。

    https://www.monotalk.xyz/static/fonts/Open-Sans-800italic/Open-Sans-800italic.woff2?5ddec16961e4: 5 issues
    [
      {
        "location": {
          "column": -1,
          "line": -1
        },
        "message": "'content-type' header should have media type 'application/font-woff2' (not 'application/x-font-woff')",
        "resource": "https://www.monotalk.xyz/static/fonts/Open-Sans-800italic/Open-Sans-800italic.woff2?5ddec16961e4",
        "ruleId": "content-type",
        "severity": 2,
        "sourceCode": null
      },
      {
        "location": {
          "column": -1,
          "line": -1
        },
        "message": "'server' header is disallowed",
        "resource": "https://www.monotalk.xyz/static/fonts/Open-Sans-800italic/Open-Sans-800italic.woff2?5ddec16961e4",
        "ruleId": "no-disallowed-headers",
        "severity": 2,
        "sourceCode": null
      },
      {
        "location": {
          "column": -1,
          "line": -1
        },
        "message": "'x-ua-compatible' header is not needed",
        "resource": "https://www.monotalk.xyz/static/fonts/Open-Sans-800italic/Open-Sans-800italic.woff2?5ddec16961e4",
        "ruleId": "no-html-only-headers",
        "severity": 2,
        "sourceCode": null
      },
      {
        "location": {
          "column": -1,
          "line": -1
        },
        "message": "'strict-transport-security' header was not specified",
        "resource": "https://www.monotalk.xyz/static/fonts/Open-Sans-800italic/Open-Sans-800italic.woff2?5ddec16961e4",
        "ruleId": "strict-transport-security",
        "severity": 2,
        "sourceCode": null
      },
      {
        "location": {
          "column": -1,
          "line": -1
        },
        "message": "'x-content-type-options' header was not specified",
        "resource": "https://www.monotalk.xyz/static/fonts/Open-Sans-800italic/Open-Sans-800italic.woff2?5ddec16961e4",
        "ruleId": "x-content-type-options",
        "severity": 2,
        "sourceCode": null
      }
    ]
    

設定変更して、再度チェックを実行

コンソールで内容を確認するには、json 形式だと見づらいので別の形式に変更、3rd party の リソースで出力される警告を OFF にします。
また、Web UI から チェック実施した際に無視したルールを除外します。

出力フォーマットを変更

  • .sonarrc を編集
    .sonarrc を編集して formatter を "stylish" に変更します。
        "formatters": [
            "stylish"
        ],
    
  • チェックを再実行

    sonar https://www.monotalk.xyz
    

  • チェック結果の抜粋
    コンソール出力に見やすい形式で出力されます。

    ✖ Finishing...
    https://www.monotalk.xyz/
                        Error  Invalid date format in 'expires' value of the 'set-cookie' header to set 'csrftoken'. The recommended format is: Mon, 29 Oct 2018 11:58:05 GMT                                                                             validate-set-cookie-header
                        Error  Manifest not specified                                                                                                                                                                                                     manifest-exists
                        Error  jQuery@2.2.4 has 2 known vulnerabilities (1 medium, 1 low). See https://snyk.io/vuln/npm:jquery for more information.                                                                                                      no-vulnerable-javascript-libraries
    line 4   col 21516  Error  Protocol relative URL found: //monotalkxyz.disqus.com/count-data.js?1=BlogPost-323&1=BlogPost-324&1=BlogPost-325&1=BlogPost-326&1=BlogPost-327&1=BlogPost-328&1=BlogPost-329&1=BlogPost-330&1=BlogPost-331&1=BlogPost-332  no-protocol-relative-urls
    line 4   col 21764  Error  Protocol relative URL found: //monotalkxyz.disqus.com/count-data.js?1=BlogPost-333&1=BlogPost-334&1=BlogPost-335&1=BlogPost-337&1=BlogPost-338&1=BlogPost-339&1=BlogPost-340&1=BlogPost-341&1=BlogPost-342&1=BlogPost-343  no-protocol-relative-urls
    line 4   col 22012  Error  Protocol relative URL found: //monotalkxyz.disqus.com/count-data.js?1=BlogPost-344&1=BlogPost-345&1=BlogPost-346&1=BlogPost-347&1=BlogPost-348                                                                             no-protocol-relative-urls
    line 5   col 20046  Error  Protocol relative URL found: //uh.nakanohito.jp/uhj2/uh.js                                                                                                                                                                 no-protocol-relative-urls
    line 5   col 21384  Error  Protocol relative URL found: //monotalkxyz.disqus.com/count.js                                                                                                                                                             no-protocol-relative-urls
    line 5   col 22996  Error  <ul> and <ol> must only directly contain <li>, <script> or <template> elements                                                                                                                                             axe
    line 16  col 205    Error  Form elements must have labels                                                                                                                                                                                             axe
    line 16  col 310    Error  Form elements must have labels                                                                                                                                                                                             axe
    line 16  col 1002   Error  Protocol relative URL found: //pagead2.googlesyndication.com/pagead/js/adsbygoogle.js                                                                                                                                      no-protocol-relative-urls
    line 16  col 1598   Error  Frames must have title attribute                                                                                                                                                                                           axe
    line 20  col 7460   Error  Elements must have sufficient color contrast                                                                                                                                                                               axe
    line 31  col 88     Error  Protocol relative URL found: //pagead2.googlesyndication.com/pagead/js/adsbygoogle.js                                                                                                                                      no-protocol-relative-urls
    line 31  col 684    Error  Frames must have title attribute                                                                                                                                                                                           axe
    line 33  col 10696  Error  Links must have discernible text                                                                                                                                                                                           axe
    line 33  col 10909  Error  Links must have discernible text                                                                                                                                                                                           axe
    line 33  col 11119  Error  Elements must have sufficient color contrast                                                                                                                                                                               axe
    ✖ Found 19 errors and 0 warnings
    
    中略.....................
    
    https://fcmatch.youtube.com/pixel?goog … cql_Xe3xhq4cSK1pDUlBdIUqmjVJtWBTQ51wpzw
    Error  'x-frame-options', 'x-xss-protection' headers are not needed  no-html-only-headers
    Error  'strict-transport-security' header was not specified          strict-transport-security
    Error  'x-content-type-options' header was not specified             x-content-type-options
    ✖ Found 3 errors and 0 warnings
    
    https://pagead2.googlesyndication.com/ … UiZYl3_X2rV4FTV0sl2De43qVlh58jk7tgEaozB
    Error  'strict-transport-security' header was not specified  strict-transport-security
    ✖ Found 1 error and 0 warnings
    
    ✖ Found a total of 181 errors and 0 warnings
    

ignore URL を追加

3rd party のリソースで警告が出力されますが、対処ができないため一律 OFF にします。

  • ignore URL に、エラーを無視したいドメインを追加
    ignoredUrls に、エラーを無視したいドメインを追加します。
    全てのルールを無視したいので、rules には ["*"] を設定しています。
  "ignoredUrls": [
        {
  "domain": "pagead2.googlesyndication.com",
  "rules": ["*"]
  },
  {
  "domain": "www.gstatic.com",
  "rules": ["*"]  
  },
  {
  "domain": "tpc.googlesyndication.com",
  "rules": ["*"]  
  },
  {
  "domain": "fonts.gstatic.com",
  "rules": ["*"]  
  },
        {
  "domain": "googleads.g.doubleclick.net",
  "rules": ["*"]  
  },
  {
  "domain": "monotalkxyz.disqus.com",
  "rules": ["*"]  
  },
  {
  "domain": "fonts.googleapis.com",
  "rules": ["*"]  
  },
  {
  "domain": "www.google-analytics.com",
  "rules": ["*"]  
  },
  {
  "domain": "securepubads.g.doubleclick.net",
  "rules": ["*"]  
  },
  {
  "domain": "uh.nakanohito.jp",
  "rules": ["*"]  
  },
  {
  "domain": "adservice.google.com",
  "rules": ["*"]  
  },
  {
  "domain": "adservice.google.co.jp",
  "rules": ["*"]  
  },
  {
  "domain": "www.googletagmanager.com",
  "rules": ["*"]  
  }
    ],
  • チェックを再実行

    sonar https://www.monotalk.xyz
    

  • チェック結果
    3rd party のドメインのエラーは出力されなくなりました。

    ✖ Finishing...
    https://www.monotalk.xyz/
                        Error    Invalid date format in 'expires' value of the 'set-cookie' header to set 'csrftoken'. The recommended format is: Mon, 29 Oct 2018 12:05:14 GMT                                                                             validate-set-cookie-header
                        Error    Manifest not specified                                                                                                                                                                                                     manifest-exists
                        Error    jQuery@2.2.4 has 2 known vulnerabilities (1 medium, 1 low). See https://snyk.io/vuln/npm:jquery for more information.                                                                                                      no-vulnerable-javascript-libraries
    line 4   col 21516  Error    Protocol relative URL found: //monotalkxyz.disqus.com/count-data.js?1=BlogPost-323&1=BlogPost-324&1=BlogPost-325&1=BlogPost-326&1=BlogPost-327&1=BlogPost-328&1=BlogPost-329&1=BlogPost-330&1=BlogPost-331&1=BlogPost-332  no-protocol-relative-urls
    line 4   col 21764  Error    Protocol relative URL found: //monotalkxyz.disqus.com/count-data.js?1=BlogPost-333&1=BlogPost-334&1=BlogPost-335&1=BlogPost-337&1=BlogPost-338&1=BlogPost-339&1=BlogPost-340&1=BlogPost-341&1=BlogPost-342&1=BlogPost-343  no-protocol-relative-urls
    line 4   col 22012  Error    Protocol relative URL found: //monotalkxyz.disqus.com/count-data.js?1=BlogPost-344&1=BlogPost-345&1=BlogPost-346&1=BlogPost-347&1=BlogPost-348                                                                             no-protocol-relative-urls
    line 5   col 20046  Error    Protocol relative URL found: //uh.nakanohito.jp/uhj2/uh.js                                                                                                                                                                 no-protocol-relative-urls
    line 5   col 21331  Error    Element “ul” not allowed as child of element “ul” in this context. (Suppressing further errors from this subtree.)                                                                                                         html-checker
    line 5   col 21384  Error    Protocol relative URL found: //monotalkxyz.disqus.com/count.js                                                                                                                                                             no-protocol-relative-urls
    line 5   col 22996  Error    <ul> and <ol> must only directly contain <li>, <script> or <template> elements                                                                                                                                             axe
    line 16  col 97     Error    Element “form” not allowed as child of element “ul” in this context. (Suppressing further errors from this subtree.)                                                                                                       html-checker
    line 16  col 205    Error    Form elements must have labels                                                                                                                                                                                             axe
    line 16  col 310    Error    Form elements must have labels                                                                                                                                                                                             axe
    line 16  col 743    Error    Element “p” not allowed as child of element “h1” in this context. (Suppressing further errors from this subtree.)                                                                                                          html-checker
    line 16  col 1002   Error    Protocol relative URL found: //pagead2.googlesyndication.com/pagead/js/adsbygoogle.js                                                                                                                                      no-protocol-relative-urls
    line 16  col 1598   Error    Frames must have title attribute                                                                                                                                                                                           axe
    line 19  col 2149   Warning  Text run is not in Unicode Normalization Form C.                                                                                                                                                                           html-checker
    line 20  col 7460   Error    Elements must have sufficient color contrast                                                                                                                                                                               axe
    line 31  col 88     Error    Protocol relative URL found: //pagead2.googlesyndication.com/pagead/js/adsbygoogle.js                                                                                                                                      no-protocol-relative-urls
    line 31  col 684    Error    Frames must have title attribute                                                                                                                                                                                           axe
    line 33  col 10696  Error    Links must have discernible text                                                                                                                                                                                           axe
    line 33  col 10909  Error    Links must have discernible text                                                                                                                                                                                           axe
    line 33  col 11119  Error    Elements must have sufficient color contrast                                                                                                                                                                               axe
    ✖ Found 22 errors and 1 warning
    
    ✖ Found a total of 22 errors and 1 warning
    

除外ルールを追加

validate-set-cookie-headerno-protocol-relative-urlsno-vulnerable-javascript-libraries は Web UI でのチェック実施時に無視していたので、除外します。
また、manifest-exists については、PWA 関連の manifest ファイル が存在しないことについての警告ですので、こちらも一旦除外します。

    "rules": {
        "amp-validator": "off",
        "apple-touch-icons": "error",
        "axe": "error",
        "content-type": "error",
        "disown-opener": "error",
        "highest-available-document-mode": "error",
        "html-checker": "error",
        "image-optimization-cloudinary": "off",
        "manifest-app-name": "error",
        "manifest-exists": "off", // off に設定
        "manifest-file-extension": "error",
        "manifest-is-valid": "error",
        "meta-charset-utf-8": "error",
        "meta-viewport": "error",
        "no-disallowed-headers": ["error",{ "ignore":["Server"] }],
        "no-friendly-error-pages": "error",
        "no-html-only-headers": "error",
        "no-protocol-relative-urls": "off", // off に設定
        "no-vulnerable-javascript-libraries": "off", // off に設定
        "ssllabs": "off",
        "strict-transport-security": "error",
        "validate-set-cookie-header": "off", // off に設定
        "x-content-type-options": "error"
    },

Web UI で実行する場合との違いについて

推奨ルールを使った場合の Web UI との適用ルールの差分について説明します。
aXe のチェック、 html-checker のチェックがかかるため、Web UI とは警告の内容が異なります。

  • aXe のチェックが効いている
    2017/10/30 時点では Web UI での aXe のチェックは実施できないようですが、CLI からは実行されており、ログに警告が出力されています。

  • “html-checker” が効いている
    Web UI だと、html の妥当性検証はかかっていなかったのですが、CLI ツールで実行すると、チェックがかかるようです。

  • “ssllabs” が “off” になっている
    Web UI だと、Qualys SSL Labs のチェックが行われますが、CLI では推奨ルールで OFF になっています。
    これは、イントラネット環境で Glogbal な Domain が割り当てられていない場合、チェックが失敗するからかと思います。

  • “image-optimization-cloudinary” が “off”
    cloudinary の api による 画像のサイズチェックも OFF になっています。
    これも、イントラネット環境で Glogbal な Domain が割り当てられていない場合、チェックが失敗するからかと思います。
    Cloudinary offers support for sonar | Cloudinary Blog

  • “amp-validator” が “off”
    これは、Web UI でも OFF になっていました。AMP ページの場合は有効にするのかと思います。


警告に対処する

出力された Found a total of 22 errors and 1 warning に対して対処していきます。
Web UI で無視していた警告は、特に触らず修正は行なっていません。

html checker の警告

以下、出力されていた html checker の警告になります。それぞれ対処していきます。

  • Error Element “ul” not allowed as child of element “ul” in this context. (Suppressing further errors from this subtree.)
    ul の 子要素として ul が使用されているという警告です。
    確かに不要な ul がありましたので削除しました。

  • Error Element “p” not allowed as child of element “h1” in this context. (Suppressing further errors from this subtree.)
    h1 の 子要素として、p タグが使われているという警告です。
    h タグの中に入れていいのはインライン要素のみなので、ブロックタグ である p タグは削除する必要があります。
    対象箇所の p タグを削除しました。1

  • Warning Text run is not in Unicode Normalization Form C.
    「Text run is not in Unicode Normalization Form C.」というHTML Validation Serviceの警告について: 小粋空間 を見る限り Unicode正規化形式C ではない文字列が混じっているとこの警告がでるようです。対象箇所をValidator.nu (X)HTML5 Validator で確認したところ、濁点まじりの文字で警告が出ているようでした。
    Pythonのunicodedata.normalize(‘NFKC’, x)で正規化される文字一覧 - めもちょう を見ると、unicodedata.normalize で正規化はできそうなので、後日やってみようかと思います。

axe の警告

続いて、axe の警告に対処します。
sonar ではエラーとしては認識できますが、実際の修正には、axe の chrome plugin や、 firefox の plugin を使ったほうが修正作業はしやすいかと思います。
私は以下の chrome plugin を使って修正作業を行いました。
aXe - Chrome ウェブストア

  • Error Form elements must have labels
    Form の input タグに label が付与されていないという警告です。
    これは Form の デザイン的に入れるのが難しいため、無視しました。

  • Error <ul> and <ol> must only directly contain <li>, <script> or <template> elements
    これは、ul タグ ol タグ の配下に含められない 要素が含まれているという警告です。
    html checker で警告が出ていた ul タグの子要素の ul タグを削除したところ解消されました。

  • Error Frames must have title attribute
    Frame タグに、title 属性が付与されていないことを示す警告です。
    タイトルがついているとスクリーンリーダが読み上げてくれるようです。
    Google Tag Manager の iframe で警告が出ていて、あまり title を設定する意味が感じられず、設定せず無視しました。2,3

  • Error Links must have discernible text
    a タグのリンクにリンクテキストがないという警告です。これもスクリーンリーダーの読み上げの対象にならないようです。
    リンクテキストを対象箇所には付与できなかったので、a タグに title 属性を付与することで対応しました。

  • Error Elements must have sufficient color contrast
    テキストと背景色のコントラストが足りないという警告になります。


再チェックを実行

警告に対処した後、再度チェックを実行したところ、以下の結果になりました。
だいぶ無視しましたが、Found a total of 9 errors and 1 warning なので、努力の甲斐はあったかと思います。

https://www.monotalk.xyz/
line 16  col 205    Error    Form elements must have labels                                                                                     axe
line 16  col 310    Error    Form elements must have labels                                                                                     axe
line 16  col 738    Error    Element “p” not allowed as child of element “h1” in this context. (Suppressing further errors from this subtree.)  html-checker
line 16  col 1593   Error    Frames must have title attribute                                                                                   axe
line 16  col 2158   Error    Frames must have title attribute                                                                                   axe
line 19  col 2149   Warning  Text run is not in Unicode Normalization Form C.                                                                   html-checker
line 20  col 7460   Error    Elements must have sufficient color contrast                                                                       axe
line 31  col 684    Error    Frames must have title attribute                                                                                   axe
line 31  col 1249   Error    Frames must have title attribute                                                                                   axe
line 33  col 11168  Error    Elements must have sufficient color contrast                                                                       axe
✖ Found a total of 9 errors and 1 warning

まとめ

sonar, a linting tool for the web の CLIツールを使ってみました。
以下まとめます。

  • Web UI とはチェックルールが異なり、axe は CLI ツールでないと現状チェックがかからない。

  • axe は Chrome plugin と併用したほうがいい。

  • output の形式がいろいろ選択できるので、CIに組み込んで実行ができそう。

  • 何回か叩いたが、何故かhtml check でエラーになることがあったり、rule を設定すると outputが微妙に変わったりする。4

  • axe、 と、 html check 初めてで勉強になった。

以上です。


  1. HTML 素人だなと我ながら思いました。もっと勉強します。
    html 上の p タグ は消すことはできたのですが、blog システムの都合上出る部分もあり、対応することを諦めました。 

  2. 目が見える人にとっても見えない隠しフレームになっているので、それを読み上げる意図を感じませんでした。 

  3. 設定している方もいるようです。Tag Manager no JavaScript WCAG 2.0 A / AA Compliance - Google プロダクト フォーラム 

  4. 多少バグっぽい動作はしますが、そんなに問題になるレベルではないかと個人的には思います。 

コメント