├── files ├── .gitignore ├── WebSphereの設定.txt ├── Kotlin.txt ├── Scala.txt ├── PHP.txt ├── Ruby.txt ├── DotNetFramework.txt ├── Go.txt ├── Nodejs.txt ├── Python.txt ├── DotNetCore.txt └── Javaエージェント.txt ├── README.md ├── requirements.txt ├── .vimrc ├── docker-compose.yml ├── Dockerfile ├── feeds ├── end_of_support.xml ├── go_support_tech_update.xml ├── php_support_tech_update.xml ├── java_support_tech_update.xml ├── ruby_support_tech_update.xml ├── python_support_tech_update.xml ├── nodejs_support_tech_update.xml ├── dotnet_core_support_tech_update.xml ├── dotnet_framework_support_tech_update.xml └── index.html ├── .github └── workflows │ ├── build.yml │ └── rss.yml └── work ├── go_rlsnote.py ├── php_rlsnote.py ├── java_rlsnote.py ├── ruby_rlsnote.py ├── python_rlsnote.py ├── dotnet_core_rlsnote.py ├── nodejs_rlsnote.py ├── nodejs_beta_rlsnote.py ├── dotnet_framework_rlsnote.py ├── nodejs_protect_rlsnote.py ├── contrast_rlsnote.py ├── contrast_rlsnote_saas.py ├── contrast_rlsnote_eop.py ├── go_support_tech.py ├── php_support_tech.py ├── ruby_support_tech.py ├── python_support_tech.py ├── nodejs_support_tech.py ├── java_support_tech.py ├── dotnet_core_support_tech.py ├── dotnet_framework_support_tech.py └── agent_end_support_chk.py /files/.gitignore: -------------------------------------------------------------------------------- 1 | *.tmp 2 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # contrast-documentation-rss 2 | -------------------------------------------------------------------------------- /files/WebSphereの設定.txt: -------------------------------------------------------------------------------- 1 | WebSphereをアプリケーションサーバとして使用している場合は、エージェントをデプロイする前に、WebsphereでJavaエージェントを設定するに記載されている情報もご確認ください。 -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | beautifulsoup4==4.12.2 2 | lxml==4.9.3 3 | feedgenerator==2.1.0 4 | django==4.2.24 5 | python-dateutil==2.9.0 6 | -------------------------------------------------------------------------------- /files/Kotlin.txt: -------------------------------------------------------------------------------- 1 | テクノロジ 2 | サポート対象バージョン 3 | Contrastエージェント 4 | 3.9.1.25108以降 5 | Javaランタイム 6 | JDK 8以上 7 | Kotlinのバージョン 8 | 1.5.x - 1.8.x -------------------------------------------------------------------------------- /.vimrc: -------------------------------------------------------------------------------- 1 | set nu 2 | set noai 3 | set nobackup 4 | set paste 5 | set expandtab 6 | set tabstop=4 7 | set shiftwidth=4 8 | set noswapfile 9 | syntax on 10 | -------------------------------------------------------------------------------- /files/Scala.txt: -------------------------------------------------------------------------------- 1 | テクノロジ 2 | サポート対象バージョン 3 | Contrastエージェント 4 | 3.8.11.23624以降 5 | Javaランタイム 6 | JDK 8以上 7 | Scalaのバージョン 8 | 2.12, 2.13 9 | Playのバージョン 10 | 2.6, 2.7, 2.8 11 | Akka HTTP 12 | 10.2.4 -------------------------------------------------------------------------------- /docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | python3: 5 | image: ghcr.io/contrast-security-oss/contrast-documentation-rss/python3:latest 6 | platform: linux/amd64 7 | build: . 8 | container_name: 'rssgen.python3' 9 | tty: true 10 | volumes: 11 | - ./work:/work 12 | - ./files:/files 13 | - ./feeds:/feeds 14 | 15 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM python:3.9.18 2 | USER root 3 | 4 | RUN apt-get update 5 | RUN apt-get -y install locales && \ 6 | localedef -f UTF-8 -i ja_JP ja_JP.UTF-8 7 | ENV LANG ja_JP.UTF-8 8 | ENV LANGUAGE ja_JP:ja 9 | ENV LC_ALL ja_JP.UTF-8 10 | ENV TZ JST-9 11 | ENV TERM xterm 12 | ENV PYTHONDONTWRITEBYTECODE 1 13 | ENV PYTHONUNBUFFERED 1 14 | 15 | RUN apt-get install -y vim less 16 | RUN pip install --upgrade pip 17 | RUN pip install --upgrade setuptools 18 | 19 | WORKDIR /work 20 | COPY ./requirements.txt /root 21 | RUN pip install -r /root/requirements.txt 22 | COPY ./.vimrc /root 23 | 24 | -------------------------------------------------------------------------------- /files/PHP.txt: -------------------------------------------------------------------------------- 1 | このエージェントでは、以下のテクノロジをサポートしています。 2 | テクノロジ 3 | サポート対象バージョン 4 | 備考 5 | 言語のバージョン 6 | 7.4、8.0、8.1、8.2、8.3、8.4 7 | エージェントは、mbstringおよびcurl拡張モジュールに依存します。 8 | NTS版のPHPのみをサポート。 9 | アプリケーションフレームワーク 10 | Laravel 6〜12 11 | Symfony 5〜7 12 | Drupal 8〜11 13 | サーバ 14 | Apache 15 | PHP-FPM 16 | その他、mod_phpやphp-fpmを使用しているサーバでも動作する可能性がありますが、現在はサポートされていません。 17 | php-fpmを使用している場合は、clear_envをnoに設定して下さい。この設定により、必要な環境変数がPHPワーカープロセスで使用できるようになります。 デフォルト値を使用すると、全てのシェル環境変数が PHP ワーカープロセスに到達する前にクリアされてしまい、 エージェントが正しく機能しなくなります。 18 | php-fpmプール設定ファイルは、通常/usr/local/etc/php-fpm.d/www.confにあります。 19 | パッケージ管理 20 | Composer 21 | SCAでサポートされています。 22 | コンテンツ管理システム 23 | WordPress 6 -------------------------------------------------------------------------------- /feeds/end_of_support.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | End of Agent support 5 | https://contrastsecurity.dev/contrast-documentation-rss 6 | End Of Agent Support 7 | 8 | ja 9 | Copyright 2024 Contrast Security Japan G.K. 10 | Mon, 05 Feb 2024 16:03:44 +0000 11 | 12 | 13 | -------------------------------------------------------------------------------- /feeds/go_support_tech_update.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Go Supported Technologies 5 | https://contrastsecurity.dev/contrast-documentation-rss 6 | Go Supported Technologies 7 | 8 | ja 9 | Copyright 2023 Contrast Security Japan G.K. 10 | Thu, 16 Nov 2023 00:00:00 -0000 11 | 12 | 13 | -------------------------------------------------------------------------------- /feeds/php_support_tech_update.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | PHP Supported Technologies 5 | https://contrastsecurity.dev/contrast-documentation-rss 6 | PHP Supported Technologies 7 | 8 | ja 9 | Copyright 2023 Contrast Security Japan G.K. 10 | Thu, 16 Nov 2023 00:00:00 -0000 11 | 12 | 13 | -------------------------------------------------------------------------------- /feeds/java_support_tech_update.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Java Supported Technologies 5 | https://contrastsecurity.dev/contrast-documentation-rss 6 | Java Supported Technologies 7 | 8 | ja 9 | Copyright 2023 Contrast Security Japan G.K. 10 | Thu, 16 Nov 2023 00:00:00 -0000 11 | 12 | 13 | -------------------------------------------------------------------------------- /feeds/ruby_support_tech_update.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Ruby Supported Technologies 5 | https://contrastsecurity.dev/contrast-documentation-rss 6 | Ruby Supported Technologies 7 | 8 | ja 9 | Copyright 2023 Contrast Security Japan G.K. 10 | Thu, 16 Nov 2023 00:00:00 -0000 11 | 12 | 13 | -------------------------------------------------------------------------------- /feeds/python_support_tech_update.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Python Supported Technologies 5 | https://contrastsecurity.dev/contrast-documentation-rss 6 | Python Supported Technologies 7 | 8 | ja 9 | Copyright 2023 Contrast Security Japan G.K. 10 | Thu, 16 Nov 2023 00:00:00 -0000 11 | 12 | 13 | -------------------------------------------------------------------------------- /feeds/nodejs_support_tech_update.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Node.js Supported Technologies 5 | https://contrastsecurity.dev/contrast-documentation-rss 6 | Node.js Supported Technologies 7 | 8 | ja 9 | Copyright 2023 Contrast Security Japan G.K. 10 | Thu, 16 Nov 2023 00:00:00 -0000 11 | 12 | 13 | -------------------------------------------------------------------------------- /feeds/dotnet_core_support_tech_update.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | .NET Core Supported Technologies 5 | https://contrastsecurity.dev/contrast-documentation-rss 6 | .NET Core Supported Technologies 7 | 8 | ja 9 | Copyright 2023 Contrast Security Japan G.K. 10 | Thu, 16 Nov 2023 00:00:00 -0000 11 | 12 | 13 | -------------------------------------------------------------------------------- /feeds/dotnet_framework_support_tech_update.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | .NET Framework Supported Technologies 5 | https://contrastsecurity.dev/contrast-documentation-rss 6 | .NET Framework Supported Technologies 7 | 8 | ja 9 | Copyright 2023 Contrast Security Japan G.K. 10 | Thu, 16 Nov 2023 00:00:00 -0000 11 | 12 | 13 | -------------------------------------------------------------------------------- /files/Ruby.txt: -------------------------------------------------------------------------------- 1 | Rubyエージェントは現在、新規のお客様への販売は行っておりません。Ruby言語の製品およびサポートについてご質問がある場合は、弊社の営業担当までお問い合わせ下さい。 2 | このエージェントでは、以下のテクノロジをサポートしています。 3 | テクノロジ 4 | サポート対象バージョン 5 | 備考 6 | 言語のバージョン 7 | 3.2.x:最初のサポート対象エージェントは6.13.0 8 | 3.1.x:最初のサポート対象エージェントは6.0.0 9 | Contrastは、通常のメンテナンスおよびセキュリティメンテナンスステータスのRuby LTS(長期サポート)バージョンをサポートします。Rubyバージョンのサポートは、ワーキンググループがLTS期間をシフトするのに合わせて変更されます。 10 | 具体的なリリース日については、Rubyメンテナンスブランチのスケジュールを参照して下さい。 11 | Rubyのサポート終了日はこちらを参照して下さい。 12 | サポート対象外: 13 | 2.5.x:最後のサポート対象エージェントは4.14.1 14 | 2.4.x:最後のサポート対象エージェントは3.9.1 15 | 2.6.x:最後のサポート対象エージェントは5.3.0 16 | 2.7.x:最後のサポート対象エージェントは6.15.3 17 | 3.0.x:最初のサポート対象エージェントは4.6.0 18 | アプリケーションフレームワーク 19 | Rails 7.x 20 | Sinatra 3.x  21 | 正式にサポートされていないRackベースのWebフレームワークでもエージェントは動作しますが、サポート対象のフレームワークの場合と比べて具体性の低い検出結果となる可能性があります。アプリケーションコード内で発生した脆弱性が報告されるのではなく、Rackメソッドと直接のインターフェイスとなるフレームワークコード内の脆弱性が報告される可能性があります。 22 | データベース 23 | MongoDB 24 | Mysql2 25 | PG 26 | SQLite3 27 | Webサーバ 28 | Passenger 5.37、6.x 29 | Puma 3.7 - 5.x 30 | Thin 1.7.2 - 1.8.x 31 | Unicorn 5.0.x - 6.x 32 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: Create and publish a Docker image 2 | 3 | on: 4 | workflow_dispatch: 5 | 6 | env: 7 | REGISTRY: ghcr.io 8 | IMAGE_NAME: contrast-security-oss/contrast-documentation-rss/python3 9 | 10 | jobs: 11 | build-and-push-image: 12 | runs-on: ubuntu-latest 13 | permissions: 14 | packages: write 15 | contents: read 16 | steps: 17 | - name: Checkout repository 18 | uses: actions/checkout@v4 19 | - name: Login to Docker 20 | uses: docker/login-action@65b78e6e13532edd9afa3aa52ac7964289d1a9c1 21 | with: 22 | registry: ${{ env.REGISTRY }} 23 | username: ${{ github.actor }} 24 | password: ${{ secrets.GITHUB_TOKEN }} 25 | - name: Extract metadata (tags, labels) for Docker 26 | id: meta 27 | uses: docker/metadata-action@9ec57ed1fcdbf14dcef7dfbe97b2010124a938b7 28 | with: 29 | images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} 30 | - name: Build and push Docker image 31 | uses: docker/build-push-action@f2a1d5e99d037542a71f64918e516c093c6f3fc4 32 | with: 33 | context: . 34 | push: true 35 | tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest 36 | 37 | -------------------------------------------------------------------------------- /files/DotNetFramework.txt: -------------------------------------------------------------------------------- 1 | Contrast .NETエージェントは、以下のテクノロジで構築されるWebアプリケーションの解析をサポートします。 2 | テクノロジ 3 | サポート対象のバージョン 4 | 注記 5 | Windows版 .NET Framework 6 | アプリケーションのランタイムバージョン 7 | 4.5以降 8 | 古いバージョンの.NET 4をアプリケーションがターゲットにしている場合でも、.NET Frameworkアプリケーションの互換性により、ほとんどのアプリケーションで最新の.NET Frameworkエージェントを使用できます。 9 | サポート対象外: 10 | Classic ASP 11 | Classic ASPのアプリケーションは.NETランタイムで動作しません。 12 | Monoランタイム 13 | Contrastエージェントは、CLRのプロファイルAPIを使用してアプリケーションを計測します。CLRプロファイルAPIは、CLRによって公開されるCOM(Component Object Model)ベースのインターフェイスです。LinuxではCOMをサポートしません。したがって、MonoはCLRプロファイルAPIをサポートしないため、ContrastはMonoをサポートできません。 14 | サーバのランタイムバージョン 15 | 4.7.1, 4.7.2, 4.8 16 | 17 | CLR 18 | CLR4 19 | 20 | Webサーバ 21 | IIS 22 | IIS Express 23 | アプリケーションフレームワーク 24 | ASP.NET MVC 3-5 25 | ASP.NET Web Forms 26 | ASP.NET Web Pages 27 | IIS-ホストのASMXベースWebサービス 28 | IISホストのWeb API 29 | IISホストのWCFサービス 30 | OWINホストのWeb API(Windowsサービスまたはコマンドラインアプリケーション経由) 31 | これらのフレームワークは、テスト済みのものを明示的に記載していますが、フレームワークが単に典型的なASP.NETクラス(例えば、System.Web.HttpRequestなど)をラップしている場合は、他のアプリケーションを解析できる場合があります。 32 | サポート対象外: 33 | .NET FrameworkのASP.NET Coreアプリケーションの解析(.NET Coreアプリケーションを解析するには.NET Coreエージェント を使用)。 34 | 部分的な信頼(trust)レベルで実行されているアプリケーション。 35 | Azure App Serviceの場合、.NET Frameworkアプリケーションは.NET Frameworkの拡張機能または NuGetパッケージを使用する必要があります。 36 | .NET Coreアプリケーションは、.NET Coreの拡張機能またはNuGetパッケージを使用する必要があります。 -------------------------------------------------------------------------------- /files/Go.txt: -------------------------------------------------------------------------------- 1 | このエージェントでは、以下のテクノロジをサポートしています。 2 | テクノロジ 3 | サポート対象バージョン 4 | 備考 5 | 言語のバージョン 6 | 1.23 7 | 1.24 8 | 1.25 9 | Contrastは、Goリリースのサポートポリシーに従います。このポリシーは、直近にリリースされた2つのメジャーバージョンをサポートします。Go言語のサポート対象バージョンは、新しいメジャーバージョンがリリースされると変わります。アプリケーションの依存関係は、go.modファイルで指定する必要があります。 10 | サポート対象外: 11 | 1.22:サポート対象だった最後のバージョンは7.3.0 12 | 1.21:サポート対象だった最後のバージョンは6.14.0 13 | 1.20:サポート対象だった最後のバージョンは6.10.0 14 | 1.19:サポート対象だった最後のバージョンは5.12.0 15 | 1.18:サポート対象だった最後のバージョンは4.2.0 16 | 1.17:サポート対象だった最後のバージョンは3.6.0 17 | 1.16:サポート対象だった最後のバージョンは3.6.0 18 | 1.15:サポート対象だった最後のバージョンは1.12.0 19 | プラットフォーム 20 | darwin/amd64 21 | darwin/arm64 22 | linux/amd64 23 | linux/arm64 24 | Contrastでは、一覧にあるプラットフォームをターゲットにしてcontrast-goをビルド・テストしています。 25 | その他のプラットフォームに対してcontrast-goをクロスコンパイルすることもできますが、互換性は保証されません。 26 | 依存関係の管理方法 27 | Go mod 28 | アプリケーションは、Go Modulesの一部である必要があります。go mod initを実行することで、アプリケーションでGo Modulesを初期化できます。 29 | プロトコルスタック 30 | net/http 31 | github.com/valyala/fasthttp v1.46.0以降 32 | google.golang.org/grpc v1.17.0以降 33 | エージェントは、プロトコルの実装に依存して、アプリケーションの動きを理解します。サポートされていないプロトコルパッケージがアプリケーションで使用されている場合、エージェントは脆弱性やルート情報を報告することができません。 34 | ルーターとフレームワーク 35 | github.com/gofiber/fiber v2.40.0以降 36 | github.com/go-chi/chi/v5 37 | github.com/julienschmidt/httprouter 38 | github.com/gin-gonic/gin v1以降 39 | github.com/go-openapi/swag 40 | github.com/labstack/echo 41 | フレームワークの基礎となるHTTP実装がサポートされている限り、この一覧にないフレームワークでもエージェントは動作します。ただし、一部の機能が使用できなくなるか、精度が低くなる可能性があります。 42 | 例えば、認識できないルータに登録されたルートを、エージェントが正しく検出しない可能性があります。 43 | ご利用のフレームワークがサポート対象のフレームワークの一覧にない場合やサポートが必要な場合は、Contrastサポートにお問い合わせください。 44 | データベースのサポート 45 | database/sql 46 | エージェントは、データベースドライバとして登録されたデータベースをサポートするために、標準ライブラリのdatabase/sqlパッケージに組み込むことができます。SQLDriversの例を参照ください。 -------------------------------------------------------------------------------- /files/Nodejs.txt: -------------------------------------------------------------------------------- 1 | このページは、備考で特に記載されていない限り、npmjs.com(npm公式Webサイト)で入手可能な最新バージョンのサポート対象テクノロジや機能を反映しています。 2 | Contrast Node.jsエージェントは、 npmjs.comで非推奨(deprecated)とタグ付けされたモジュールでは機能しない場合があります。非推奨のモジュールは、セキュリティ上のリスクが高く、エージェントの機能に悪影響を及ぼす可能性があります。 3 | また、webpack、parcel、esbuildなどのバンドラーを使用してサーバサイドのJavaScriptコードをパッケージ化したり圧縮したりするアプリケーションもサポートしません。 4 | テクノロジ 5 | サポート対象バージョン 6 | 備考 7 | 言語のバージョン 8 | JavaScript ECMAScript 5 9 | JavaScript ECMAScript 6 10 | ECMAScriptモジュール(ESM) 11 | TypeScript 12 | Contrastは、「アクティブLTS」または「メンテナンスLTS」ステータスのNode.jsの偶数番号バージョンをサポートします。 13 | Node.js LTSバージョンは、JavaScript ECMAScript5と6の機能をサポートします。 14 | TypeScriptがサポートされるのは、エージェントがアプリケーションのコンパイル済みエントリポイントを指すように設定されている場合のみです。 15 | システム 16 | Node.js LTSバージョン18、20 、22、24 17 | プロセッサのサポート - Apple M1/M2、Intel/AMD(AMD64) 18 | オペレーティングシステムのサポート - Windows Server、 Windows 10/11、MacOS、Linux (Debian、CentOSなど) 19 | PM2 20 | Node.jsエージェントのシステム要件 21 | Node.js LTS 22に対応しているNode.js エージェントのバージョンは、5.xのみとなります。 22 | NPMバージョン 23 | 8.5.5以降 24 | 25 | アプリケーションフレームワーク 26 | Express 4、5 27 | Fastify 3、4、5 28 | Hapi 19、20、21 29 | Koa 2.3以降 30 | Restify 8、9、10、11 31 | 32 | データベースドライバとオブジェクト関係マッピング(ORM) 33 | MarsDB 現在はメンテナンスされていないが、脆弱なJuiceShopアプリケーションには必要。 34 | Mongoose 6.x、7.x、8.x 35 | MongoDB 2.2.36、3.3.0以降、4.x、5.x(データベースバージョン4.x、5.x、6.xに対応) 36 | MySQL2 2.0.0以降(MySQLデータベースバージョン5.6.51、5.7.x、8.0.xに対応) 37 | MSSQL 6.4.0以降 38 | Postgresドライバ 7.5.0以降、8.x 39 | Sequelize 5.x(こちらは保守管理者によって非推奨)、6.x 40 | SQLite3ドライバ 4.x(データベースバージョン3.26.0以降に対応)これは主にJuiceShopやデモアプリのためのものであり、SQLiteは「本番用」のデータベースではありません。 41 | MongoDB 2.2.36は、脆弱なNodeGoatアプリケーションで必要とされる場合のみ、サポートされています。 42 | SQLiteとMarsDBは本番環境で使用するのではなく、脆弱なJuiceShopアプリケーションの実行やテストを可能にするためにのみサポートされています。 43 | 検証パッケージ/ライブラリ 44 | Class-validator 0.13.0以降 45 | Joi 17以降 46 | Validator 13以降 47 | 48 | テンプレートエンジン 49 | Pug 3 50 | EJS 3.x 51 | 52 | その他のパッケージ/ライブラリ 53 | Express-session 1.15.6、1.16.0以降 54 | 55 | その他のテクノロジ 56 | HTTP/2 57 | GraphQL:graphql、@apollo/server、graphql-yoga 58 | -------------------------------------------------------------------------------- /files/Python.txt: -------------------------------------------------------------------------------- 1 | このエージェントでは、以下のテクノロジをサポートしています。 2 | テクノロジ 3 | サポート対象バージョン 4 | 備考 5 | 言語のバージョン 6 | 3.13.x:最初にサポート対象となったエージェントは9.8.0 7 | 3.12.x:最初にサポート対象となったエージェントは5.27.0 8 | 3.11.x:最初にサポート対象となったエージェントは5.19.0 9 | 3.10.x:最初にサポート対象となったエージェントは5.2.0 10 | 3.9.x:最初にサポート対象となったエージェントは4.2.0 11 | Contrastは、バグフィックスおよび セキュリティステータスのPython LTS(長期サポート)バージョンをサポートします。Pythonバージョンのサポートは、ワーキンググループがLTS期間をシフトするのに合わせて行われます。 12 | サポート対象外: 13 | 3.6.x、3.5x、2.7.x:サポートする最後のバージョンは4.14.3 14 | 3.7.x:サポートする最後のバージョンは5.27.0 15 | 3.8.x:サポートする最後のバージョンは9.8.0 16 | Contrastは現在、Pythonの実験的なJITコンパイラやフリースレッドをサポートしていません。これらの機能が有効になっている環境ではエージェントは動作しません。 17 | 18 | アプリケーションフレームワーク 19 | Aiohttp: 3.7 - 3.9 20 | Bottle: 0.13 21 | Django: 3.2 - 5.2 22 | Django Rest Framework: 3.12 - 3.15 23 | Falcon: 3.0 - 3.1 24 | FastAPI: 0.71 - 0.118 25 | Flask: 1.1 - 3.1 26 | Pyramid: 1.10 - 2.0 27 | Quart:0.15 - 0.20 28 | Starlette: 0.17 - 0.49 29 | Pythonエージェントは、WSGI互換を意図して作られています。ガイドラインに従う限り、他のWSGIアプリケーションと互換性がある可能性があります。 30 | また、PythonエージェントはDjango、FastAPI、QuartなどのASGIインターフェイスを提供するフレームワークとも互換性があります。 31 | FastAPIおよびStarlette(FastAPIが依存している)は比較的新しいライブラリで、継続的な開発変更が行われているため、Contrastが対応できなくなる可能性があります。FastAPIは、開発スピードが速いとされています。 Contrastは記載のバージョンまでサポートを続け、新しいサポート対象がリリースされたときはドキュメントを更新します。 32 | ここでは簡略化のためにマイクロ/パッチバージョンが省略されていますが、各マイナーバージョンシリーズ内の最新パッチを使用することを推奨します。例えば、3.2はPyPIで利用可能なパッケージの最新の3.2.xを指します。 33 | プラットフォーム 34 | darwin/amd64 35 | darwin/arm64 36 | linux/amd64 37 | Alpineシステムでは、libgccが必要です。apk add libgccでインストールできます。 38 | Webサーバ 39 | Gunicorn 0.16.1 –21.2.x 40 | uWSGI 2.0.14 - 2.0.x 41 | Uvicorn 0.14.x - 0.23.x 42 | The Python agent supports all versions. 43 | データベース 44 | Mongo (pymongo) 45 | MySQL (PyMySQL、mysql-connector) 46 | PostgreSQL (psycopg2) 47 | [en] SQLAlchemy (dbapi2-compliant adapters) 48 | SQLite3 (sqlite3、pysqlite2) 49 | [en] The Stored XSS Assess rule requires Django’s built-in ORM. 50 | リクエスト処理ロジックをアプリケーションの __main__モジュールに置くことは避けて下さい。Contrastで十分に観測できない可能性があります。最適なカバレッジを得るためには、アプリケーションを直接呼び出す(例:python app.pyやpython -m app)のではなく、 標準的なWebサーバ( サポート対象のWebサーバを参照)を使用してサーバを起動することをお勧めします。これは稀なケースですが、検出精度を最大限に高めるためには考慮すべき点です。 -------------------------------------------------------------------------------- /files/DotNetCore.txt: -------------------------------------------------------------------------------- 1 | このエージェントでは、以下のテクノロジをサポートします。 2 | テクノロジ 3 | サポート対象バージョン 4 | 備考 5 | アプリケーションフレームワーク 6 | ASP.NET Core(6.0、8.0、9.0、10.0) 7 | Model-View-Controller (MVC) 8 | Razor Pages 9 | Grpc.AspNetCore 10 | Blazor(6.0、8.0、9.0、10/0) 11 | Blazor Server(サーバ側)のみで、Blazor WebAssemblyはサポートされません 12 | SignalR(6.0、8.0、9.0、10.0) 13 | トランスポートプロトコル:WebSocket、サーバ送信イベント(SSE)、ロングポーリング 14 | サポート対象外: 15 | .NET CoreまたはASP.NET Coreバージョン2.1以前 16 | .NET Framework (Windows)またはMono (Linux/Windows)上で動作するASP.NET Coreアプリケーション 17 | Grpc.Core 18 | gRPCドキュメントのThe future of gRPC in C# belongs to grpc-dotnet(C#でのgRPCにgrpc-dotnetを推奨)に、詳細情報があります。 19 | ランタイム 20 | .NET Coreランタイム:6.0、 8.0、 9.0、 10.0 21 | .NET Coreターゲットフレームワーク : 22 | net6.0 23 | net8.0 24 | net9.0 25 | net10.0 26 | サポート対象外: 27 | ランタイムよりも上位バージョンのASP.NET Coreアプリケーションでの実行(例、ASP.NET Core 5.0を参照する.NET Core 3.1ランタイムのアプリケーションなど) 28 | 参照するASP.NET Coreのバージョンとコンパイル時に選択したターゲットのランタイムが一致しない.NET Coreアプリケーションでの実行 29 | Windows版.NET Core 30 | Windowsオペレーティングシステム 31 | Windows Server (LTSC) (x86, x64):2012 R2、2016、2019、2022 32 | Windows Server (SAC) (x64):1809、1903 33 | Windowsワークステーション(x86、x64):7、8/8.1、10 34 | 64ビットシステムでは、エージェントを使用して32ビットと64ビットの両方のWebアプリケーションを解析できます。 35 | サポート対象外: 36 | ARM版Windows 37 | サーバコンテナ 38 | Kestrel、IISHttpServer 39 | サポート対象外: 40 | Http.sys (旧WebListener) 41 | ホスティングコンテナ 42 | セルフホスト、IIS、IIS Express 43 | 44 | Linux OS版.NET Core 45 | Linuxオペレーティングシステム 46 | Ubuntu:18.04以降(x64、ARM64) 47 | Debian:10以降(x64、ARM64) 48 | openSUSE:15以降(x64) 49 | Alpine:3.13以降(x64、ARM64) 50 | CentOS Stream 8以降(x64) 51 | Red Hat Enterprise Linux:7以降(x64) 52 | サポート対象外: Red Hat Enterprise Linux 6 53 | サーバコンテナ 54 | Kestrel 55 | 56 | ホスティングコンテナ 57 | セルフホスト 58 | 59 | .NET Core 2.2は、.NET Coreエージェントのバージョン1.5.20以降ではサポートされません。.NET Core 2.2を使用している場合、アプリケーションの.NET Coreランタイムをアップグレードするまでは、.NET Coreエージェントのバージョン1.5.20以前のものを使用してください。 60 | NET Coreエージェントのバージョン1.9.9をもって、.NET Core 2.1のサポートを終了しました。.NET Core 2.1を使用している場合、アプリケーションの.NET Coreランタイムをアップグレードするまでは、.NET Coreエージェントのバージョン1.9.9以前のものを使用してください。 61 | Microsoftは、2022年5月10日をもって.NET 5.0のサポートを終了し、2022年12月13日をもって.NET Core 3.1のサポートを終了しました。.NET 5.0および.NET Core 3.1に関するContrastのサポートは、.NET Coreエージェントのバージョン3.0.0による限定的なサポートとなります。Contrastの限定サポートでは、サポート対象の言語バージョンで再現可能な問題のみを解決します。お使いのアプリケーションを.NETのサポート対象バージョンにアップグレードすることを強く推奨します。 62 | .NET Coreエージェントは、System.RuntimeおよびASPNET Coreを参照していないアプリケーションをサポートしません。また、エージェントが依存しているアセンブリをコンパイラがトリムする可能性があるため、エージェントはトリミングされた自己完結型のデプロイと実行可能ファイルもサポートしません。 -------------------------------------------------------------------------------- /files/Javaエージェント.txt: -------------------------------------------------------------------------------- 1 | テクノロジ 2 | サポート対象バージョン 3 | 備考 4 | Javaランタイム 5 | IBM 8 6 | Oracle 8 *バージョン11以降はOpenJDKのサポートに従う 7 | OpenJDK 8、11、12、13、14、15、16、17、18、19、20、21、23、24、25 8 | OpenJDKのサポートは、ここに示す現在のサポート対象バージョンの範囲内で、全ての公開中のビルドで動作するように設計されています。一般的によく利用されるAzulやAmazon Correttoなどもサポート対象のJDKのカテゴリに入ります。 9 | サポート対象外: 10 | JDKプレビュー機能 11 | 旧JavaエージェントのJavaランタイム 12 | Javaエージェント3.xのみでの使用 13 | IBM 6、7 14 | Oracle 6、7 15 | OpenJDK 6、7 16 | 参考 17 | サポート速報:Java6およびJava7のサポート終了について 18 | FAQ:Java6およびJava7のサポート終了について 19 | アプリケーションサーバ 20 | GlassFish 4、5、6 21 | Grizzly 2.3.20以降 22 | JBoss EAP 6.xおよび7.x 23 | Jetty 7、8、9、10、11 24 | Karaf 3.0.x 25 | Netty 4.x 26 | Payara 5、6 27 | Play 2.4 28 | Resin 4 29 | Tomcat 5、6、7、8、9 、10 30 | Vert.x 3.1.0 、4.x 31 | WebLogic 10、11g、12c、14 32 | WebSphere* 8.5、9.0 33 | WebSphere Liberty 22 、23、24 34 | WildFly 10、11、14、18、23-32 35 | * zSeriesおよびAIXの環境ではサポートが限定されます。SPARC SolarisでWebSphereを使用する場合、バージョン8.5.5.11が必須となります。 36 | ルートカバレッジのサポート: 37 | GlassFish 4、5、6 38 | Jetty 11.0、10.0、9.4、8.1、7.6 39 | Resin 4.0 40 | Tomcat 5、6、7、8、9、10 41 | WebLogic 12、14 42 | WebSphere 8.5、9.0 43 | WildFly 10、11、14、18、23-32 44 | オプティマイザ 45 | Proguard 46 | ProguardにあるJavaバイトコードの最適化機能は、Contrastのようなランタイムエージェントが基本前提とする動きに反します。Proguardユーザが、Contrastを利用してアプリケーションを保護する場合は、Proguardの-dontoptimize設定オプションを使用して最適化を行わないようにする必要があります。 47 | データベース 48 | DB2 49 | DynamoDB 50 | MySQL 51 | Oracle 52 | PostgreSQL 53 | SQL Server 54 | SQLite JDBCドライバ 55 | [en] 56 | メッセージサービス 57 | Contrast Assessのみが以下のメッセージサービスをサポートしています。 58 | JMS 2.0 59 | IBM MQ 9.x 60 | Spring JMS 2.x 61 | エージェントのバージョン:Java 4.7.0以降 62 | Contrastのバージョン:3.9.9以降 63 | Kafkaストリーミング 64 | エージェントのバージョン: Java 5.0.0以降 65 | その他のJavaテクノロジ 66 | ADF JSF 67 | Apache POI、Fileupload、HttpComponents 68 | Axis (RPC)、XMLRPC、RMI、Apache CXF、JMS (javax.jms) 69 | Direct Web Remoting (DWR) 70 | DropWizard 71 | Freemarker 72 | Glowroot* 73 | GSON、Kryo、minidev、org.json 74 | Google Web Toolkit (GWT) 75 | gRPC 1.4.x、1.5.x、1.6.x 76 | Hibernate 6.2 - 6.4 77 | http4k(4.6.0.0と4.17、Contrast Assess対象) 78 | J2SE 79 | JDBC、JDBI、MongoDB 80 | JSF (MyFaces、RichFaces、Sun) 81 | java.nio、java.beans 82 | Java EE/J2EE、Servlet/JSP 83 | Jersey 84 | MyBatis 85 | OWASP ESAPI、AntiSamy、Coverity 86 | PrimeFaces 87 | Quarkus RESTEasy 88 | Seam 89 | Spring 3.2-3.5、Spring Boot、Spring AOP 90 | Spring Cloud 91 | Spring WebFlux 5および6 92 | Spring Web Services 93 | Struts、Struts 2、Struts 7 compatibility with Assess 94 | Wicket 95 | XStream、Jackson (JSON/XML) 96 | Xerces、JAXB、nu.xom 97 | * Glowrootを使用する場合、glowroot.jarよりも前に、Contrastエージェントのjarを指定して、ロードする必要があります。 98 | ルートカバレッジのサポート: 99 | http4k-core 4.17 100 | http4k-core 4.6 101 | Jersey  2.25、2.28、2.36、2.6 102 | Quarkus RESTeasy 2.15 103 | Spring Web MVC 4.2、5.3、6.0 104 | Spring WebFlux 5および6 105 | Spring Web Services 106 | Struts 2 -------------------------------------------------------------------------------- /work/go_rlsnote.py: -------------------------------------------------------------------------------- 1 | import urllib.request as req 2 | from bs4 import BeautifulSoup 3 | import xml.dom.minidom 4 | from django.utils.feedgenerator import Rss201rev2Feed 5 | from datetime import datetime 6 | import locale 7 | import html 8 | import hashlib 9 | 10 | def main(): 11 | locale.setlocale(locale.LC_TIME, "C") 12 | url = 'https://docs.contrastsecurity.jp/ja/go-agent-release-notes-and-archive.html' 13 | res = req.urlopen(url) 14 | soup = BeautifulSoup(res, 'lxml') 15 | elems = soup.select('section.section.accordion') 16 | modified_date = soup.select_one('span.formatted-date').text.strip() 17 | 18 | feed = Rss201rev2Feed( 19 | title='Go Agent Release Note', 20 | link='https://contrastsecurity.dev/contrast-documentation-rss', 21 | description='Go Agent Release Note', 22 | language='ja', 23 | author_name="Contrast Security Japan G.K.", 24 | feed_url='https://contrastsecurity.dev/contrast-documentation-rss/go_rlsnote.xml', 25 | feed_copyright='Copyright 2023 Contrast Security Japan G.K.' 26 | ) 27 | for elem in elems: 28 | try: 29 | id_str = elem.get("id") 30 | #pubdate_str = elem.get("data-publication-date") # November 6, 2023 31 | pubdate_str = elem.get("data-time-modified") # November 6, 2023 32 | pubdate = None 33 | if pubdate_str: 34 | pubdate = datetime.strptime(pubdate_str, '%B %d, %Y') 35 | title = elem.select('h3.title')[0].text.strip() 36 | if not title.lower().startswith('go'): 37 | continue 38 | #desc = elem.select('div.panel-body')[0].text 39 | desc_buffer = [] 40 | #for elem2 in elem.select('p, div'): 41 | for elem2 in elem.select('p'): 42 | if elem2.parent.name == 'li': 43 | desc_buffer.append('・%s' % elem2.text) 44 | else: 45 | desc_buffer.append('%s' % elem2.text) 46 | #print(elem2.text) 47 | id_hash = hashlib.md5(id_str.encode()).hexdigest() 48 | url = 'https://docs.contrastsecurity.jp/ja/go-agent-release-notes-and-archive.html#%s' % id_str 49 | guid = 'https://docs.contrastsecurity.jp/ja/go-agent-release-notes-and-archive.html#%s' % id_hash 50 | if not 'リリース日' in ''.join(desc_buffer): 51 | continue 52 | feed.add_item(title=title, link=url, description=''.join(['

{0}

'.format(s) for s in desc_buffer]), pubdate=pubdate, unique_id=guid) 53 | except IndexError: 54 | continue 55 | 56 | str_val = feed.writeString('utf-8') 57 | dom = xml.dom.minidom.parseString(str_val) 58 | with open('/feeds/go_rlsnote.xml','w') as fp: 59 | dom.writexml(fp, encoding='utf-8', newl='\n', indent='', addindent=' ') 60 | 61 | if __name__ == "__main__": 62 | main() 63 | 64 | -------------------------------------------------------------------------------- /work/php_rlsnote.py: -------------------------------------------------------------------------------- 1 | import urllib.request as req 2 | from bs4 import BeautifulSoup 3 | import xml.dom.minidom 4 | from django.utils.feedgenerator import Rss201rev2Feed 5 | from datetime import datetime 6 | import locale 7 | import html 8 | import hashlib 9 | 10 | def main(): 11 | locale.setlocale(locale.LC_TIME, "C") 12 | url = 'https://docs.contrastsecurity.jp/ja/php-agent-release-notes-and-archive.html' 13 | res = req.urlopen(url) 14 | soup = BeautifulSoup(res, 'lxml') 15 | elems = soup.select('section.section.accordion') 16 | modified_date = soup.select_one('span.formatted-date').text.strip() 17 | 18 | feed = Rss201rev2Feed( 19 | title='PHP Agent Release Note', 20 | link='https://contrastsecurity.dev/contrast-documentation-rss', 21 | description='PHP Agent Release Note', 22 | language='ja', 23 | author_name="Contrast Security Japan G.K.", 24 | feed_url='https://contrastsecurity.dev/contrast-documentation-rss/php_rlsnote.xml', 25 | feed_copyright='Copyright 2023 Contrast Security Japan G.K.' 26 | ) 27 | for elem in elems: 28 | try: 29 | id_str = elem.get("id") 30 | #pubdate_str = elem.get("data-publication-date") # November 6, 2023 31 | pubdate_str = elem.get("data-time-modified") # November 6, 2023 32 | pubdate = None 33 | if pubdate_str: 34 | pubdate = datetime.strptime(pubdate_str, '%B %d, %Y') 35 | title = elem.select('h3.title')[0].text.strip() 36 | if not title.lower().startswith('php'): 37 | continue 38 | #desc = elem.select('div.panel-body')[0].text 39 | desc_buffer = [] 40 | #for elem2 in elem.select('p, div'): 41 | for elem2 in elem.select('p'): 42 | if elem2.parent.name == 'li': 43 | desc_buffer.append('・%s' % elem2.text) 44 | else: 45 | desc_buffer.append('%s' % elem2.text) 46 | #print(elem2.text) 47 | id_hash = hashlib.md5(id_str.encode()).hexdigest() 48 | url = 'https://docs.contrastsecurity.jp/ja/php-agent-release-notes-and-archive.html#%s' % id_str 49 | guid = 'https://docs.contrastsecurity.jp/ja/php-agent-release-notes-and-archive.html#%s' % id_hash 50 | if not 'リリース日' in ''.join(desc_buffer): 51 | continue 52 | feed.add_item(title=title, link=url, description=''.join(['

{0}

'.format(s) for s in desc_buffer]), pubdate=pubdate, unique_id=guid) 53 | except IndexError: 54 | continue 55 | 56 | str_val = feed.writeString('utf-8') 57 | dom = xml.dom.minidom.parseString(str_val) 58 | with open('/feeds/php_rlsnote.xml','w') as fp: 59 | dom.writexml(fp, encoding='utf-8', newl='\n', indent='', addindent=' ') 60 | 61 | if __name__ == "__main__": 62 | main() 63 | 64 | -------------------------------------------------------------------------------- /work/java_rlsnote.py: -------------------------------------------------------------------------------- 1 | import urllib.request as req 2 | from bs4 import BeautifulSoup 3 | import xml.dom.minidom 4 | from django.utils.feedgenerator import Rss201rev2Feed 5 | from datetime import datetime 6 | import locale 7 | import html 8 | import hashlib 9 | 10 | def main(): 11 | locale.setlocale(locale.LC_TIME, "C") 12 | url = 'https://docs.contrastsecurity.jp/ja/java-agent-release-notes-and-archive.html' 13 | res = req.urlopen(url) 14 | soup = BeautifulSoup(res, 'lxml') 15 | elems = soup.select('section.section.accordion') 16 | modified_date = soup.select_one('span.formatted-date').text.strip() 17 | 18 | feed = Rss201rev2Feed( 19 | title='Java Agent Release Note', 20 | link='https://contrastsecurity.dev/contrast-documentation-rss', 21 | description='Java Agent Release Note', 22 | language='ja', 23 | author_name="Contrast Security Japan G.K.", 24 | feed_url='https://contrastsecurity.dev/contrast-documentation-rss/java_rlsnote.xml', 25 | feed_copyright='Copyright 2023 Contrast Security Japan G.K.' 26 | ) 27 | for elem in elems: 28 | try: 29 | id_str = elem.get("id") 30 | #pubdate_str = elem.get("data-publication-date") # November 6, 2023 31 | pubdate_str = elem.get("data-time-modified") # November 6, 2023 32 | pubdate = None 33 | if pubdate_str: 34 | pubdate = datetime.strptime(pubdate_str, '%B %d, %Y') 35 | title = elem.select('h3.title')[0].text.strip() 36 | if not title.lower().startswith('java'): 37 | continue 38 | #desc = elem.select('div.panel-body')[0].text 39 | desc_buffer = [] 40 | #for elem2 in elem.select('p, div'): 41 | for elem2 in elem.select('p'): 42 | if elem2.parent.name == 'li': 43 | desc_buffer.append('・%s' % elem2.text) 44 | else: 45 | desc_buffer.append('%s' % elem2.text) 46 | #print(elem2.text) 47 | id_hash = hashlib.md5(id_str.encode()).hexdigest() 48 | url = 'https://docs.contrastsecurity.jp/ja/java-agent-release-notes-and-archive.html#%s' % id_str 49 | guid = 'https://docs.contrastsecurity.jp/ja/java-agent-release-notes-and-archive.html#%s' % id_hash 50 | if not 'リリース日' in ''.join(desc_buffer): 51 | continue 52 | feed.add_item(title=title, link=url, description=''.join(['

{0}

'.format(s) for s in desc_buffer]), pubdate=pubdate, unique_id=guid) 53 | except IndexError: 54 | continue 55 | 56 | str_val = feed.writeString('utf-8') 57 | dom = xml.dom.minidom.parseString(str_val) 58 | with open('/feeds/java_rlsnote.xml','w') as fp: 59 | dom.writexml(fp, encoding='utf-8', newl='\n', indent='', addindent=' ') 60 | 61 | if __name__ == "__main__": 62 | main() 63 | 64 | -------------------------------------------------------------------------------- /work/ruby_rlsnote.py: -------------------------------------------------------------------------------- 1 | import urllib.request as req 2 | from bs4 import BeautifulSoup 3 | import xml.dom.minidom 4 | from django.utils.feedgenerator import Rss201rev2Feed 5 | from datetime import datetime 6 | import locale 7 | import html 8 | import hashlib 9 | 10 | def main(): 11 | locale.setlocale(locale.LC_TIME, "C") 12 | url = 'https://docs.contrastsecurity.jp/ja/ruby-agent-release-notes-and-archive.html' 13 | res = req.urlopen(url) 14 | soup = BeautifulSoup(res, 'lxml') 15 | elems = soup.select('section.section.accordion') 16 | modified_date = soup.select_one('span.formatted-date').text.strip() 17 | 18 | feed = Rss201rev2Feed( 19 | title='Ruby Agent Release Note', 20 | link='https://contrastsecurity.dev/contrast-documentation-rss', 21 | description='Ruby Agent Release Note', 22 | language='ja', 23 | author_name="Contrast Security Japan G.K.", 24 | feed_url='https://contrastsecurity.dev/contrast-documentation-rss/ruby_rlsnote.xml', 25 | feed_copyright='Copyright 2023 Contrast Security Japan G.K.' 26 | ) 27 | for elem in elems: 28 | try: 29 | id_str = elem.get("id") 30 | #pubdate_str = elem.get("data-publication-date") # November 6, 2023 31 | pubdate_str = elem.get("data-time-modified") # November 6, 2023 32 | pubdate = None 33 | if pubdate_str: 34 | pubdate = datetime.strptime(pubdate_str, '%B %d, %Y') 35 | title = elem.select('h3.title')[0].text.strip() 36 | if not title.lower().startswith('ruby'): 37 | continue 38 | #desc = elem.select('div.panel-body')[0].text 39 | desc_buffer = [] 40 | #for elem2 in elem.select('p, div'): 41 | for elem2 in elem.select('p'): 42 | if elem2.parent.name == 'li': 43 | desc_buffer.append('・%s' % elem2.text) 44 | else: 45 | desc_buffer.append('%s' % elem2.text) 46 | #print(elem2.text) 47 | id_hash = hashlib.md5(id_str.encode()).hexdigest() 48 | url = 'https://docs.contrastsecurity.jp/ja/ruby-agent-release-notes-and-archive.html#%s' % id_str 49 | guid = 'https://docs.contrastsecurity.jp/ja/ruby-agent-release-notes-and-archive.html#%s' % id_hash 50 | if not 'リリース日' in ''.join(desc_buffer): 51 | continue 52 | feed.add_item(title=title, link=url, description=''.join(['

{0}

'.format(s) for s in desc_buffer]), pubdate=pubdate, unique_id=guid) 53 | except IndexError: 54 | continue 55 | 56 | str_val = feed.writeString('utf-8') 57 | dom = xml.dom.minidom.parseString(str_val) 58 | with open('/feeds/ruby_rlsnote.xml','w') as fp: 59 | dom.writexml(fp, encoding='utf-8', newl='\n', indent='', addindent=' ') 60 | 61 | if __name__ == "__main__": 62 | main() 63 | 64 | -------------------------------------------------------------------------------- /work/python_rlsnote.py: -------------------------------------------------------------------------------- 1 | import urllib.request as req 2 | from bs4 import BeautifulSoup 3 | import xml.dom.minidom 4 | from django.utils.feedgenerator import Rss201rev2Feed 5 | from datetime import datetime 6 | import locale 7 | import html 8 | import hashlib 9 | 10 | def main(): 11 | locale.setlocale(locale.LC_TIME, "C") 12 | url = 'https://docs.contrastsecurity.jp/ja/python-agent-release-notes-and-archive.html' 13 | res = req.urlopen(url) 14 | soup = BeautifulSoup(res, 'lxml') 15 | elems = soup.select('section.section.accordion') 16 | modified_date = soup.select_one('span.formatted-date').text.strip() 17 | 18 | feed = Rss201rev2Feed( 19 | title='Python Agent Release Note', 20 | link='https://contrastsecurity.dev/contrast-documentation-rss', 21 | description='Python Agent Release Note', 22 | language='ja', 23 | author_name="Contrast Security Japan G.K.", 24 | feed_url='https://contrastsecurity.dev/contrast-documentation-rss/python_rlsnote.xml', 25 | feed_copyright='Copyright 2023 Contrast Security Japan G.K.' 26 | ) 27 | for elem in elems: 28 | try: 29 | id_str = elem.get("id") 30 | #pubdate_str = elem.get("data-publication-date") # November 6, 2023 31 | pubdate_str = elem.get("data-time-modified") # November 6, 2023 32 | pubdate = None 33 | if pubdate_str: 34 | pubdate = datetime.strptime(pubdate_str, '%B %d, %Y') 35 | title = elem.select('h3.title')[0].text.strip() 36 | if not title.lower().startswith('python'): 37 | continue 38 | #desc = elem.select('div.panel-body')[0].text 39 | desc_buffer = [] 40 | #for elem2 in elem.select('p, div'): 41 | for elem2 in elem.select('p'): 42 | if elem2.parent.name == 'li': 43 | desc_buffer.append('・%s' % elem2.text) 44 | else: 45 | desc_buffer.append('%s' % elem2.text) 46 | #print(elem2.text) 47 | id_hash = hashlib.md5(id_str.encode()).hexdigest() 48 | url = 'https://docs.contrastsecurity.jp/ja/python-agent-release-notes-and-archive.html#%s' % id_str 49 | guid = 'https://docs.contrastsecurity.jp/ja/python-agent-release-notes-and-archive.html#%s' % id_hash 50 | if not 'リリース日' in ''.join(desc_buffer): 51 | continue 52 | feed.add_item(title=title, link=url, description=''.join(['

{0}

'.format(s) for s in desc_buffer]), pubdate=pubdate, unique_id=guid) 53 | except IndexError: 54 | continue 55 | 56 | str_val = feed.writeString('utf-8') 57 | dom = xml.dom.minidom.parseString(str_val) 58 | with open('/feeds/python_rlsnote.xml','w') as fp: 59 | dom.writexml(fp, encoding='utf-8', newl='\n', indent='', addindent=' ') 60 | 61 | if __name__ == "__main__": 62 | main() 63 | 64 | -------------------------------------------------------------------------------- /work/dotnet_core_rlsnote.py: -------------------------------------------------------------------------------- 1 | import urllib.request as req 2 | from bs4 import BeautifulSoup 3 | import xml.dom.minidom 4 | from django.utils.feedgenerator import Rss201rev2Feed 5 | from datetime import datetime 6 | import locale 7 | import html 8 | import hashlib 9 | 10 | def main(): 11 | locale.setlocale(locale.LC_TIME, "C") 12 | url = 'https://docs.contrastsecurity.jp/ja/-net-core-agent-release-notes-and-archive.html' 13 | res = req.urlopen(url) 14 | soup = BeautifulSoup(res, 'lxml') 15 | elems = soup.select('section.section.accordion') 16 | modified_date = soup.select_one('span.formatted-date').text.strip() 17 | 18 | feed = Rss201rev2Feed( 19 | title='.NET Core Agent Release Note', 20 | link='https://contrastsecurity.dev/contrast-documentation-rss', 21 | description='.NET Core Agent Release Note', 22 | language='ja', 23 | author_name="Contrast Security Japan G.K.", 24 | feed_url='https://contrastsecurity.dev/contrast-documentation-rss/dotnet_core_rlsnote.xml', 25 | feed_copyright='Copyright 2023 Contrast Security Japan G.K.' 26 | ) 27 | for elem in elems: 28 | try: 29 | id_str = elem.get("id") 30 | #pubdate_str = elem.get("data-publication-date") # November 6, 2023 31 | pubdate_str = elem.get("data-time-modified") # November 6, 2023 32 | pubdate = None 33 | if pubdate_str: 34 | pubdate = datetime.strptime(pubdate_str, '%B %d, %Y') 35 | title = elem.select('h3.title')[0].text.strip() 36 | if not title.lower().startswith('.net'): 37 | continue 38 | #desc = elem.select('div.panel-body')[0].text 39 | desc_buffer = [] 40 | #for elem2 in elem.select('p, div'): 41 | for elem2 in elem.select('p'): 42 | if elem2.parent.name == 'li': 43 | desc_buffer.append('・%s' % elem2.text) 44 | else: 45 | desc_buffer.append('%s' % elem2.text) 46 | #print(elem2.text) 47 | id_hash = hashlib.md5(id_str.encode()).hexdigest() 48 | url = 'https://docs.contrastsecurity.jp/ja/-net-core-agent-release-notes-and-archive.html#%s' % id_str 49 | guid = 'https://docs.contrastsecurity.jp/ja/-net-core-agent-release-notes-and-archive.html#%s' % id_hash 50 | if not 'リリース日' in ''.join(desc_buffer): 51 | continue 52 | feed.add_item(title=title, link=url, description=''.join(['

{0}

'.format(html.escape(s)) for s in desc_buffer]), pubdate=pubdate, unique_id=guid) 53 | except IndexError: 54 | continue 55 | 56 | str_val = feed.writeString('utf-8') 57 | dom = xml.dom.minidom.parseString(str_val) 58 | with open('/feeds/dotnet_core_rlsnote.xml','w') as fp: 59 | dom.writexml(fp, encoding='utf-8', newl='\n', indent='', addindent=' ') 60 | 61 | if __name__ == "__main__": 62 | main() 63 | 64 | -------------------------------------------------------------------------------- /work/nodejs_rlsnote.py: -------------------------------------------------------------------------------- 1 | import urllib.request as req 2 | from bs4 import BeautifulSoup 3 | import xml.dom.minidom 4 | from django.utils.feedgenerator import Rss201rev2Feed 5 | from datetime import datetime 6 | import locale 7 | import html 8 | import hashlib 9 | import re 10 | 11 | def main(): 12 | locale.setlocale(locale.LC_TIME, "C") 13 | url = 'https://docs.contrastsecurity.jp/ja/node-js-agent-release-notes-and-archive.html' 14 | res = req.urlopen(url) 15 | soup = BeautifulSoup(res, 'lxml') 16 | elems = soup.select('section.section.accordion') 17 | modified_date = soup.select_one('span.formatted-date').text.strip() 18 | 19 | feed = Rss201rev2Feed( 20 | title='Node.js Agent Release Note', 21 | link='https://contrastsecurity.dev/contrast-documentation-rss', 22 | description='Node.js Agent Release Note', 23 | language='ja', 24 | author_name="Contrast Security Japan G.K.", 25 | feed_url='https://contrastsecurity.dev/contrast-documentation-rss/nodejs_rlsnote.xml', 26 | feed_copyright='Copyright 2023 Contrast Security Japan G.K.' 27 | ) 28 | for elem in elems: 29 | try: 30 | id_str = elem.get("id") 31 | #pubdate_str = elem.get("data-publication-date") # November 6, 2023 32 | pubdate_str = elem.get("data-time-modified") # November 6, 2023 33 | pubdate = None 34 | if pubdate_str: 35 | pubdate = datetime.strptime(pubdate_str, '%B %d, %Y') 36 | title = elem.select('h3.title')[0].text.strip() 37 | if not title.lower().startswith('node') or re.search(r'\d$', title) is None: # ベータも無視 38 | continue 39 | #desc = elem.select('div.panel-body')[0].text 40 | desc_buffer = [] 41 | #for elem2 in elem.select('p, div'): 42 | for elem2 in elem.select('p'): 43 | if elem2.parent.name == 'li': 44 | desc_buffer.append('・%s' % elem2.text) 45 | else: 46 | desc_buffer.append('%s' % elem2.text) 47 | #print(elem2.text) 48 | id_hash = hashlib.md5(id_str.encode()).hexdigest() 49 | url = 'https://docs.contrastsecurity.jp/ja/node-js-agent-release-notes-and-archive.html#%s' % id_str 50 | guid = 'https://docs.contrastsecurity.jp/ja/node-js-agent-release-notes-and-archive.html#%s' % id_hash 51 | if not 'リリース日' in ''.join(desc_buffer): 52 | continue 53 | feed.add_item(title=title, link=url, description=''.join(['

{0}

'.format(s) for s in desc_buffer]), pubdate=pubdate, unique_id=guid) 54 | except IndexError: 55 | continue 56 | 57 | str_val = feed.writeString('utf-8') 58 | dom = xml.dom.minidom.parseString(str_val) 59 | with open('/feeds/nodejs_rlsnote.xml','w') as fp: 60 | dom.writexml(fp, encoding='utf-8', newl='\n', indent='', addindent=' ') 61 | 62 | if __name__ == "__main__": 63 | main() 64 | 65 | -------------------------------------------------------------------------------- /work/nodejs_beta_rlsnote.py: -------------------------------------------------------------------------------- 1 | import urllib.request as req 2 | from bs4 import BeautifulSoup 3 | import xml.dom.minidom 4 | from django.utils.feedgenerator import Rss201rev2Feed 5 | from datetime import datetime 6 | import locale 7 | import html 8 | import hashlib 9 | import re 10 | 11 | def main(): 12 | locale.setlocale(locale.LC_TIME, "C") 13 | url = 'https://docs.contrastsecurity.jp/ja/node-js-agent-release-notes-and-archive.html' 14 | res = req.urlopen(url) 15 | soup = BeautifulSoup(res, 'lxml') 16 | elems = soup.select('section.section.accordion') 17 | modified_date = soup.select_one('span.formatted-date').text.strip() 18 | 19 | feed = Rss201rev2Feed( 20 | title='Node.js Agent Beta Release Note', 21 | link='https://contrastsecurity.dev/contrast-documentation-rss', 22 | description='Node.js Agent Beta Release Note', 23 | language='ja', 24 | author_name="Contrast Security Japan G.K.", 25 | feed_url='https://contrastsecurity.dev/contrast-documentation-rss/nodejs_beta_rlsnote.xml', 26 | feed_copyright='Copyright 2023 Contrast Security Japan G.K.' 27 | ) 28 | for elem in elems: 29 | try: 30 | id_str = elem.get("id") 31 | #pubdate_str = elem.get("data-publication-date") # November 6, 2023 32 | pubdate_str = elem.get("data-time-modified") # November 6, 2023 33 | pubdate = None 34 | if pubdate_str: 35 | pubdate = datetime.strptime(pubdate_str, '%B %d, %Y') 36 | title = elem.select('h4.title')[0].text.strip() 37 | if not (title.lower().startswith('node') and re.search(r'\d$', id_str)): 38 | continue 39 | #desc = elem.select('div.panel-body')[0].text 40 | desc_buffer = [] 41 | #for elem2 in elem.select('p, div'): 42 | for elem2 in elem.select('p'): 43 | if elem2.parent.name == 'li': 44 | desc_buffer.append('・%s' % elem2.text) 45 | else: 46 | desc_buffer.append('%s' % elem2.text) 47 | #print(elem2.text) 48 | id_hash = hashlib.md5(id_str.encode()).hexdigest() 49 | url = 'https://docs.contrastsecurity.jp/ja/node-js-agent-release-notes-and-archive.html#%s' % id_str 50 | guid = 'https://docs.contrastsecurity.jp/ja/node-js-agent-release-notes-and-archive.html#%s' % id_hash 51 | if not 'リリース日' in ''.join(desc_buffer): 52 | continue 53 | feed.add_item(title=title, link=url, description=''.join(['

{0}

'.format(s) for s in desc_buffer]), pubdate=pubdate, unique_id=guid) 54 | except IndexError: 55 | continue 56 | 57 | str_val = feed.writeString('utf-8') 58 | dom = xml.dom.minidom.parseString(str_val) 59 | with open('/feeds/nodejs_beta_rlsnote.xml','w') as fp: 60 | dom.writexml(fp, encoding='utf-8', newl='\n', indent='', addindent=' ') 61 | 62 | if __name__ == "__main__": 63 | main() 64 | 65 | -------------------------------------------------------------------------------- /work/dotnet_framework_rlsnote.py: -------------------------------------------------------------------------------- 1 | import urllib.request as req 2 | from bs4 import BeautifulSoup 3 | import xml.dom.minidom 4 | from django.utils.feedgenerator import Rss201rev2Feed 5 | from datetime import datetime 6 | import locale 7 | import html 8 | import hashlib 9 | 10 | def main(): 11 | locale.setlocale(locale.LC_TIME, "C") 12 | url = 'https://docs.contrastsecurity.jp/ja/-net-framework-agent-release-notes-and-archive.html' 13 | res = req.urlopen(url) 14 | soup = BeautifulSoup(res, 'lxml') 15 | elems = soup.select('section.section.accordion') 16 | modified_date = soup.select_one('span.formatted-date').text.strip() 17 | 18 | feed = Rss201rev2Feed( 19 | title='.NET Framework Agent Release Note', 20 | link='https://contrastsecurity.dev/contrast-documentation-rss', 21 | description='.NET Framework Agent Release Note', 22 | language='ja', 23 | author_name="Contrast Security Japan G.K.", 24 | feed_url='https://contrastsecurity.dev/contrast-documentation-rss/dotnet_framework_rlsnote.xml', 25 | feed_copyright='Copyright 2023 Contrast Security Japan G.K.' 26 | ) 27 | for elem in elems: 28 | try: 29 | id_str = elem.get("id") 30 | #pubdate_str = elem.get("data-publication-date") # November 6, 2023 31 | pubdate_str = elem.get("data-time-modified") # November 6, 2023 32 | pubdate = None 33 | if pubdate_str: 34 | pubdate = datetime.strptime(pubdate_str, '%B %d, %Y') 35 | title = elem.select('h3.title')[0].text.strip() 36 | if not title.lower().startswith('.net'): 37 | continue 38 | #desc = elem.select('div.panel-body')[0].text 39 | desc_buffer = [] 40 | #for elem2 in elem.select('p, div'): 41 | for elem2 in elem.select('p'): 42 | if elem2.parent.name == 'li': 43 | desc_buffer.append('・%s' % elem2.text) 44 | else: 45 | desc_buffer.append('%s' % elem2.text) 46 | #print(elem2.text) 47 | id_hash = hashlib.md5(id_str.encode()).hexdigest() 48 | url = 'https://docs.contrastsecurity.jp/ja/-net-framework-agent-release-notes-and-archive.html#%s' % id_str 49 | guid = 'https://docs.contrastsecurity.jp/ja/-net-framework-agent-release-notes-and-archive.html#%s' % id_hash 50 | if not 'リリース日' in ''.join(desc_buffer): 51 | continue 52 | feed.add_item(title=title, link=url, description=''.join(['

{0}

'.format(html.escape(s)) for s in desc_buffer]), pubdate=pubdate, unique_id=guid) 53 | except IndexError: 54 | continue 55 | 56 | str_val = feed.writeString('utf-8') 57 | dom = xml.dom.minidom.parseString(str_val) 58 | with open('/feeds/dotnet_framework_rlsnote.xml','w') as fp: 59 | dom.writexml(fp, encoding='utf-8', newl='\n', indent='', addindent=' ') 60 | 61 | if __name__ == "__main__": 62 | main() 63 | 64 | -------------------------------------------------------------------------------- /work/nodejs_protect_rlsnote.py: -------------------------------------------------------------------------------- 1 | import urllib.request as req 2 | from bs4 import BeautifulSoup 3 | import xml.dom.minidom 4 | from django.utils.feedgenerator import Rss201rev2Feed 5 | from datetime import datetime 6 | import locale 7 | import html 8 | import hashlib 9 | import re 10 | 11 | def main(): 12 | locale.setlocale(locale.LC_TIME, "C") 13 | url = 'https://docs.contrastsecurity.jp/ja/node-js-agent-release-notes-and-archive.html' 14 | res = req.urlopen(url) 15 | soup = BeautifulSoup(res, 'lxml') 16 | elems = soup.select('section.section.accordion') 17 | modified_date = soup.select_one('span.formatted-date').text.strip() 18 | 19 | feed = Rss201rev2Feed( 20 | title='Node.js Agent Protect Release Note', 21 | link='https://contrastsecurity.dev/contrast-documentation-rss', 22 | description='Node.js Agent Protect Release Note', 23 | language='ja', 24 | author_name="Contrast Security Japan G.K.", 25 | feed_url='https://contrastsecurity.dev/contrast-documentation-rss/nodejs_protect_rlsnote.xml', 26 | feed_copyright='Copyright 2023 Contrast Security Japan G.K.' 27 | ) 28 | for elem in elems: 29 | try: 30 | id_str = elem.get("id") 31 | #pubdate_str = elem.get("data-publication-date") # November 6, 2023 32 | pubdate_str = elem.get("data-time-modified") # November 6, 2023 33 | pubdate = None 34 | if pubdate_str: 35 | pubdate = datetime.strptime(pubdate_str, '%B %d, %Y') 36 | title = elem.select('h4.title')[0].text.strip() 37 | if not (title.lower().startswith('node') and re.search(r'protect$', id_str)): 38 | continue 39 | #desc = elem.select('div.panel-body')[0].text 40 | desc_buffer = [] 41 | #for elem2 in elem.select('p, div'): 42 | for elem2 in elem.select('p'): 43 | if elem2.parent.name == 'li': 44 | desc_buffer.append('・%s' % elem2.text) 45 | else: 46 | desc_buffer.append('%s' % elem2.text) 47 | #print(elem2.text) 48 | id_hash = hashlib.md5(id_str.encode()).hexdigest() 49 | url = 'https://docs.contrastsecurity.jp/ja/node-js-agent-release-notes-and-archive.html#%s' % id_str 50 | guid = 'https://docs.contrastsecurity.jp/ja/node-js-agent-release-notes-and-archive.html#%s' % id_hash 51 | if not 'リリース日' in ''.join(desc_buffer): 52 | continue 53 | feed.add_item(title=title, link=url, description=''.join(['

{0}

'.format(s) for s in desc_buffer]), pubdate=pubdate, unique_id=guid) 54 | except IndexError: 55 | continue 56 | 57 | str_val = feed.writeString('utf-8') 58 | dom = xml.dom.minidom.parseString(str_val) 59 | with open('/feeds/nodejs_protect_rlsnote.xml','w') as fp: 60 | dom.writexml(fp, encoding='utf-8', newl='\n', indent='', addindent=' ') 61 | 62 | if __name__ == "__main__": 63 | main() 64 | 65 | -------------------------------------------------------------------------------- /work/contrast_rlsnote.py: -------------------------------------------------------------------------------- 1 | import urllib.request as req 2 | from bs4 import BeautifulSoup 3 | import xml.dom.minidom 4 | from django.utils.feedgenerator import Rss201rev2Feed 5 | from datetime import datetime 6 | import locale 7 | import re 8 | import html 9 | import hashlib 10 | 11 | def main(): 12 | url = 'https://docs.contrastsecurity.jp/ja/release.html' 13 | res = req.urlopen(url) 14 | soup = BeautifulSoup(res, 'lxml') 15 | elems = soup.select('section.section') 16 | modified_date = soup.select_one('span.formatted-date').text.strip() 17 | #print(modified_date) 18 | 19 | feed = Rss201rev2Feed( 20 | title='Contrast Release Note', 21 | link='https://contrastsecurity.dev/contrast-documentation-rss', 22 | description='Contrast Release Note', 23 | language='ja', 24 | author_name="Contrast Security Japan G.K.", 25 | feed_url='https://contrastsecurity.dev/contrast-documentation-rss/contrast_rlsnote.xml', 26 | feed_copyright='Copyright 2023 Contrast Security Japan G.K.' 27 | ) 28 | 29 | id_ptn = re.compile(r'^[0-9]{1,2}月-[0-9\-]+-$') 30 | title_ptn = re.compile(r'^[0-9]{1,2}月\([0-9\.]+\)$') 31 | 32 | for elem in elems: 33 | try: 34 | id_str = elem.get("id").strip() 35 | title = elem.select('h3.title')[0].text.strip() 36 | if not id_ptn.search(id_str) or not title_ptn.search(title): 37 | continue 38 | pubdate_str = elem.get("data-time-modified") # November 6, 2023 39 | pubdate = None 40 | if pubdate_str: 41 | pubdate = datetime.strptime(pubdate_str, '%B %d, %Y') 42 | #print(id_str, pubdate_str, title) 43 | desc_buffer = [] 44 | for elem2 in elem.select('section.section'): 45 | id_str2 = elem2.get("id").strip() 46 | #print('- ', elem2.select_one('div.titlepage').text) 47 | desc_buffer.append('%s' % elem2.select_one('div.titlepage').text) 48 | for elem3 in elem2.select('li.listitem'): 49 | #print(' - ', elem3.select_one('p').text) 50 | desc_buffer.append('・%s' % elem3.select_one('p').text) 51 | #print(id_str, elem.get('data-legacy-id')) 52 | #if not title.lower().startswith('java'): 53 | # continue 54 | id_hash = hashlib.md5(id_str.encode()).hexdigest() 55 | url = 'https://docs.contrastsecurity.jp/ja/release.html#%s' % id_str 56 | guid = 'https://docs.contrastsecurity.jp/ja/release.html#%s' % id_hash 57 | if not '月' in title: 58 | continue 59 | feed.add_item(title=title, link=url, description=''.join(['

{0}

'.format(s) for s in desc_buffer]), pubdate=pubdate, unique_id=guid) 60 | except IndexError: 61 | continue 62 | str_val = feed.writeString('utf-8') 63 | dom = xml.dom.minidom.parseString(str_val) 64 | with open('/feeds/contrast_rlsnote.xml','w') as fp: 65 | dom.writexml(fp, encoding='utf-8', newl='\n', indent='', addindent=' ') 66 | 67 | if __name__ == "__main__": 68 | main() 69 | 70 | -------------------------------------------------------------------------------- /work/contrast_rlsnote_saas.py: -------------------------------------------------------------------------------- 1 | import urllib.request as req 2 | from bs4 import BeautifulSoup 3 | import xml.dom.minidom 4 | from django.utils.feedgenerator import Rss201rev2Feed 5 | from datetime import datetime 6 | import locale 7 | import re 8 | import html 9 | import hashlib 10 | 11 | def main(): 12 | url = 'https://docs.contrastsecurity.jp/ja/release-hosted.html' 13 | res = req.urlopen(url) 14 | soup = BeautifulSoup(res, 'lxml') 15 | elems = soup.select('section.section') 16 | modified_date = soup.select_one('span.formatted-date').text.strip() 17 | #print(modified_date) 18 | 19 | feed = Rss201rev2Feed( 20 | title='Contrast Release Note(SaaS)', 21 | link='https://contrastsecurity.dev/contrast-documentation-rss', 22 | description='Contrast Release Note(SaaS)', 23 | language='ja', 24 | author_name="Contrast Security Japan G.K.", 25 | feed_url='https://contrastsecurity.dev/contrast-documentation-rss/contrast_rlsnote_saas.xml', 26 | feed_copyright='Copyright 2023 Contrast Security Japan G.K.' 27 | ) 28 | 29 | id_ptn = re.compile(r'^20[0-9]{2}年[0-9]{1,2}月$') 30 | title_ptn = re.compile(r'^20[0-9]{2}年[0-9]{1,2}月$') 31 | 32 | for elem in elems: 33 | try: 34 | id_str = elem.get("id").strip() 35 | title = elem.select('h3.title')[0].text.strip() 36 | if not id_ptn.search(id_str) or not title_ptn.search(title): 37 | continue 38 | pubdate_str = elem.get("data-time-modified") # November 6, 2023 39 | pubdate = None 40 | if pubdate_str: 41 | pubdate = datetime.strptime(pubdate_str, '%B %d, %Y') 42 | #print(id_str, pubdate_str, title) 43 | desc_buffer = [] 44 | for elem2 in elem.select('section.section'): 45 | id_str2 = elem2.get("id").strip() 46 | #print('- ', elem2.select_one('div.titlepage').text) 47 | desc_buffer.append('%s' % elem2.select_one('div.titlepage').text) 48 | for elem3 in elem2.select('li.listitem'): 49 | #print(' - ', elem3.select_one('p').text) 50 | desc_buffer.append('・%s' % elem3.select_one('p').text) 51 | #print(id_str, elem.get('data-legacy-id')) 52 | #if not title.lower().startswith('java'): 53 | # continue 54 | id_hash = hashlib.md5(id_str.encode()).hexdigest() 55 | url = 'https://docs.contrastsecurity.jp/ja/release-hosted.html#%s' % id_str 56 | guid = 'https://docs.contrastsecurity.jp/ja/release-hosted.html#%s' % id_hash 57 | if not '月' in title: 58 | continue 59 | feed.add_item(title=title, link=url, description=''.join(['

{0}

'.format(s) for s in desc_buffer]), pubdate=pubdate, unique_id=guid) 60 | except IndexError: 61 | continue 62 | str_val = feed.writeString('utf-8') 63 | dom = xml.dom.minidom.parseString(str_val) 64 | with open('/feeds/contrast_rlsnote_saas.xml','w') as fp: 65 | dom.writexml(fp, encoding='utf-8', newl='\n', indent='', addindent=' ') 66 | 67 | if __name__ == "__main__": 68 | main() 69 | 70 | -------------------------------------------------------------------------------- /work/contrast_rlsnote_eop.py: -------------------------------------------------------------------------------- 1 | import urllib.request as req 2 | from bs4 import BeautifulSoup 3 | import xml.dom.minidom 4 | from django.utils.feedgenerator import Rss201rev2Feed 5 | from datetime import datetime 6 | import locale 7 | import re 8 | import html 9 | import hashlib 10 | 11 | def main(): 12 | url = 'https://docs.contrastsecurity.jp/ja/release-on-premises.html' 13 | res = req.urlopen(url) 14 | soup = BeautifulSoup(res, 'lxml') 15 | elems = soup.select('section.section') 16 | modified_date = soup.select_one('span.formatted-date').text.strip() 17 | #print(modified_date) 18 | 19 | feed = Rss201rev2Feed( 20 | title='Contrast Release Note(On-premises)', 21 | link='https://contrastsecurity.dev/contrast-documentation-rss', 22 | description='Contrast Release Note(On-premises)', 23 | language='ja', 24 | author_name="Contrast Security Japan G.K.", 25 | feed_url='https://contrastsecurity.dev/contrast-documentation-rss/contrast_rlsnote_eop.xml', 26 | feed_copyright='Copyright 2023 Contrast Security Japan G.K.' 27 | ) 28 | 29 | id_ptn = re.compile(r'^[0-9]{1,2}月-[0-9\-]+-$') 30 | title_ptn = re.compile(r'^[0-9]{1,2}月\([0-9\.]+\)$') 31 | 32 | for elem in elems: 33 | try: 34 | id_str = elem.get("id").strip() 35 | title = elem.select('h3.title')[0].text.strip() 36 | if not id_ptn.search(id_str) or not title_ptn.search(title): 37 | continue 38 | pubdate_str = elem.get("data-time-modified") # November 6, 2023 39 | pubdate = None 40 | if pubdate_str: 41 | pubdate = datetime.strptime(pubdate_str, '%B %d, %Y') 42 | #print(id_str, pubdate_str, title) 43 | desc_buffer = [] 44 | for elem2 in elem.select('section.section'): 45 | id_str2 = elem2.get("id").strip() 46 | #print('- ', elem2.select_one('div.titlepage').text) 47 | desc_buffer.append('%s' % elem2.select_one('div.titlepage').text) 48 | for elem3 in elem2.select('li.listitem'): 49 | #print(' - ', elem3.select_one('p').text) 50 | desc_buffer.append('・%s' % elem3.select_one('p').text) 51 | #print(id_str, elem.get('data-legacy-id')) 52 | #if not title.lower().startswith('java'): 53 | # continue 54 | id_hash = hashlib.md5(id_str.encode()).hexdigest() 55 | url = 'https://docs.contrastsecurity.jp/ja/release-on-premises.html#%s' % id_str 56 | guid = 'https://docs.contrastsecurity.jp/ja/release-on-premises.html#%s' % id_hash 57 | if not '月' in title: 58 | continue 59 | feed.add_item(title=title, link=url, description=''.join(['

{0}

'.format(s) for s in desc_buffer]), pubdate=pubdate, unique_id=guid) 60 | except IndexError: 61 | continue 62 | str_val = feed.writeString('utf-8') 63 | dom = xml.dom.minidom.parseString(str_val) 64 | with open('/feeds/contrast_rlsnote_eop.xml','w') as fp: 65 | dom.writexml(fp, encoding='utf-8', newl='\n', indent='', addindent=' ') 66 | 67 | if __name__ == "__main__": 68 | main() 69 | 70 | -------------------------------------------------------------------------------- /.github/workflows/rss.yml: -------------------------------------------------------------------------------- 1 | name: RSS Feed Generator 2 | 3 | on: 4 | schedule: 5 | - cron: "0 0 * * *" 6 | workflow_dispatch: 7 | inputs: 8 | today: 9 | type: string 10 | required: false 11 | description: 'date(YYYY-MM-DD) for end of support check' 12 | 13 | jobs: 14 | rssgen: 15 | runs-on: ubuntu-latest 16 | permissions: 17 | packages: read 18 | pages: write 19 | contents: write 20 | steps: 21 | - name: Checkout code 22 | uses: actions/checkout@v4 23 | - name: Login to Docker 24 | uses: docker/login-action@v3 25 | with: 26 | registry: ghcr.io 27 | username: ${{ github.actor }} 28 | password: ${{ secrets.GITHUB_TOKEN }} 29 | env: 30 | OWNER: ${{ github.repository_owner }} 31 | - name: Pull Docker Image 32 | run: | 33 | docker pull ghcr.io/contrast-security-oss/contrast-documentation-rss/python3:latest 34 | - name: Generate RSS by Python 35 | run: | 36 | docker compose run python3 python java_rlsnote.py 37 | docker compose run python3 python dotnet_framework_rlsnote.py 38 | docker compose run python3 python dotnet_core_rlsnote.py 39 | docker compose run python3 python nodejs_rlsnote.py 40 | docker compose run python3 python nodejs_beta_rlsnote.py 41 | docker compose run python3 python nodejs_protect_rlsnote.py 42 | docker compose run python3 python go_rlsnote.py 43 | docker compose run python3 python python_rlsnote.py 44 | docker compose run python3 python ruby_rlsnote.py 45 | docker compose run python3 python php_rlsnote.py 46 | docker compose run python3 python contrast_rlsnote_saas.py 47 | docker compose run python3 python contrast_rlsnote_eop.py 48 | docker compose run python3 python java_support_tech.py 49 | docker compose run python3 python dotnet_framework_support_tech.py 50 | docker compose run python3 python dotnet_core_support_tech.py 51 | docker compose run python3 python nodejs_support_tech.py 52 | docker compose run python3 python go_support_tech.py 53 | docker compose run python3 python python_support_tech.py 54 | docker compose run python3 python ruby_support_tech.py 55 | docker compose run python3 python php_support_tech.py 56 | docker compose run -e TODAY=${{ github.event.inputs.today }} python3 python agent_end_support_chk.py 57 | - name: Commit updated files 58 | run: | 59 | git config core.filemode false 60 | if ! git diff --exit-code --quiet ./files 61 | then 62 | git config user.name Taka Shiozaki 63 | git config user.email taka.shiozaki@contrastsecurity.com 64 | git commit -m "Commit updated files" ./files/*.txt 65 | git push 66 | fi 67 | - uses: actions/upload-artifact@v4 68 | with: 69 | name: rss_feeds 70 | path: feeds 71 | - uses: actions/upload-pages-artifact@v3 72 | with: 73 | path: feeds 74 | deploy: 75 | needs: rssgen 76 | runs-on: ubuntu-latest 77 | environment: 78 | name: github-pages 79 | url: ${{ steps.deployment.outputs.page_url }} 80 | permissions: 81 | pages: write 82 | id-token: write 83 | steps: 84 | - uses: actions/deploy-pages@v4 85 | id: deployment 86 | 87 | -------------------------------------------------------------------------------- /work/go_support_tech.py: -------------------------------------------------------------------------------- 1 | import urllib.request as req 2 | from bs4 import BeautifulSoup 3 | import xml.dom.minidom 4 | from django.utils.feedgenerator import Rss201rev2Feed 5 | from datetime import datetime 6 | import locale 7 | import re 8 | import difflib 9 | import shutil 10 | import html 11 | import hashlib 12 | 13 | def main(): 14 | url = 'https://docs.contrastsecurity.jp/ja/go-supported-technologies.html' 15 | res = req.urlopen(url) 16 | soup = BeautifulSoup(res, 'lxml') 17 | elems = soup.select('section.section') 18 | modified_date = soup.select_one('span.formatted-date').text.strip() 19 | title = 'Go' 20 | 21 | feed = Rss201rev2Feed( 22 | title='Go Supported Technologies', 23 | link='https://contrastsecurity.dev/contrast-documentation-rss', 24 | description='Go Supported Technologies', 25 | language='ja', 26 | author_name="Contrast Security Japan G.K.", 27 | feed_url='https://contrastsecurity.dev/contrast-documentation-rss/go_support_tech_update.xml', 28 | feed_copyright='Copyright 2023 Contrast Security Japan G.K.' 29 | ) 30 | 31 | write_flg = False 32 | item_dict = {} 33 | pubdate = None 34 | for elem in elems: 35 | try: 36 | if elem.parent.name == 'div': 37 | pubdate_str = elem.get("data-time-modified") # November 6, 2023 38 | if pubdate_str: 39 | pubdate = datetime.strptime(pubdate_str, '%B %d, %Y') 40 | #continue 41 | id_str = elem.get("id") 42 | id_hash = hashlib.md5(id_str.encode()).hexdigest() 43 | url = 'https://docs.contrastsecurity.jp/ja/go-supported-technologies.html#%s' % id_str 44 | guid = 'https://docs.contrastsecurity.jp/ja/go-supported-technologies.html#%s' % id_hash 45 | text_buffer = [] 46 | for elem2 in elem.select('p'): 47 | text_buffer.append(elem2.text) 48 | with open('/files/%s.tmp' % title,'w') as fp: 49 | fp.write('\n'.join(text_buffer)) 50 | before_text = None 51 | try: 52 | with open('/files/%s.txt' % title,'r') as fp: 53 | before_text = fp.readlines() 54 | except FileNotFoundError: 55 | shutil.move('/files/%s.tmp' % title, '/files/%s.txt' % title) 56 | continue 57 | after_text = None 58 | with open('/files/%s.tmp' % title,'r') as fp: 59 | after_text = fp.readlines() 60 | res = difflib.unified_diff(before_text, after_text) 61 | res_str = '\n'.join(res) 62 | if (len(res_str.strip()) > 0): 63 | print('Found diff: ', title) 64 | item_dict[title] = (url, res_str, guid) 65 | shutil.move('/files/%s.tmp' % title, '/files/%s.txt' % title) 66 | except IndexError: 67 | continue 68 | 69 | if pubdate is None: 70 | pubdate = datetime.date.today() 71 | for k, v in item_dict.items(): 72 | feed.add_item(title=k, link=v[0], description=''.join(['

{0}

'.format(s) for s in v[1].splitlines()]), pubdate=pubdate, unique_id=v[2]) 73 | 74 | if len(item_dict) > 0: 75 | str_val = feed.writeString('utf-8') 76 | dom = xml.dom.minidom.parseString(str_val) 77 | with open('/feeds/go_support_tech_update.xml','w') as fp: 78 | dom.writexml(fp, encoding='utf-8', newl='\n', indent='', addindent=' ') 79 | 80 | if __name__ == "__main__": 81 | main() 82 | 83 | -------------------------------------------------------------------------------- /work/php_support_tech.py: -------------------------------------------------------------------------------- 1 | import urllib.request as req 2 | from bs4 import BeautifulSoup 3 | import xml.dom.minidom 4 | from django.utils.feedgenerator import Rss201rev2Feed 5 | from datetime import datetime 6 | import locale 7 | import re 8 | import difflib 9 | import shutil 10 | import html 11 | import hashlib 12 | 13 | def main(): 14 | url = 'https://docs.contrastsecurity.jp/ja/php-supported-technologies.html' 15 | res = req.urlopen(url) 16 | soup = BeautifulSoup(res, 'lxml') 17 | elems = soup.select('section.section') 18 | modified_date = soup.select_one('span.formatted-date').text.strip() 19 | title = 'PHP' 20 | 21 | feed = Rss201rev2Feed( 22 | title='PHP Supported Technologies', 23 | link='https://contrastsecurity.dev/contrast-documentation-rss', 24 | description='PHP Supported Technologies', 25 | language='ja', 26 | author_name="Contrast Security Japan G.K.", 27 | feed_url='https://contrastsecurity.dev/contrast-documentation-rss/php_support_tech_update.xml', 28 | feed_copyright='Copyright 2023 Contrast Security Japan G.K.' 29 | ) 30 | 31 | write_flg = False 32 | item_dict = {} 33 | pubdate = None 34 | for elem in elems: 35 | try: 36 | if elem.parent.name == 'div': 37 | pubdate_str = elem.get("data-time-modified") # November 6, 2023 38 | if pubdate_str: 39 | pubdate = datetime.strptime(pubdate_str, '%B %d, %Y') 40 | #continue 41 | id_str = elem.get("id") 42 | id_hash = hashlib.md5(id_str.encode()).hexdigest() 43 | url = 'https://docs.contrastsecurity.jp/ja/php-supported-technologies.html#%s' % id_str 44 | guid = 'https://docs.contrastsecurity.jp/ja/php-supported-technologies.html#%s' % id_hash 45 | text_buffer = [] 46 | for elem2 in elem.select('p'): 47 | text_buffer.append(elem2.text) 48 | with open('/files/%s.tmp' % title,'w') as fp: 49 | fp.write('\n'.join(text_buffer)) 50 | before_text = None 51 | try: 52 | with open('/files/%s.txt' % title,'r') as fp: 53 | before_text = fp.readlines() 54 | except FileNotFoundError: 55 | shutil.move('/files/%s.tmp' % title, '/files/%s.txt' % title) 56 | continue 57 | after_text = None 58 | with open('/files/%s.tmp' % title,'r') as fp: 59 | after_text = fp.readlines() 60 | res = difflib.unified_diff(before_text, after_text) 61 | res_str = '\n'.join(res) 62 | if (len(res_str.strip()) > 0): 63 | print('Found diff: ', title) 64 | item_dict[title] = (url, res_str, guid) 65 | shutil.move('/files/%s.tmp' % title, '/files/%s.txt' % title) 66 | except IndexError: 67 | continue 68 | 69 | if pubdate is None: 70 | pubdate = datetime.date.today() 71 | for k, v in item_dict.items(): 72 | feed.add_item(title=k, link=v[0], description=''.join(['

{0}

'.format(s) for s in v[1].splitlines()]), pubdate=pubdate, unique_id=v[2]) 73 | 74 | if len(item_dict) > 0: 75 | str_val = feed.writeString('utf-8') 76 | dom = xml.dom.minidom.parseString(str_val) 77 | with open('/feeds/php_support_tech_update.xml','w') as fp: 78 | dom.writexml(fp, encoding='utf-8', newl='\n', indent='', addindent=' ') 79 | 80 | if __name__ == "__main__": 81 | main() 82 | 83 | -------------------------------------------------------------------------------- /work/ruby_support_tech.py: -------------------------------------------------------------------------------- 1 | import urllib.request as req 2 | from bs4 import BeautifulSoup 3 | import xml.dom.minidom 4 | from django.utils.feedgenerator import Rss201rev2Feed 5 | from datetime import datetime 6 | import locale 7 | import re 8 | import difflib 9 | import shutil 10 | import html 11 | import hashlib 12 | 13 | def main(): 14 | url = 'https://docs.contrastsecurity.jp/ja/ruby-supported-technologies.html' 15 | res = req.urlopen(url) 16 | soup = BeautifulSoup(res, 'lxml') 17 | elems = soup.select('section.section') 18 | modified_date = soup.select_one('span.formatted-date').text.strip() 19 | title = 'Ruby' 20 | 21 | feed = Rss201rev2Feed( 22 | title='Ruby Supported Technologies', 23 | link='https://contrastsecurity.dev/contrast-documentation-rss', 24 | description='Ruby Supported Technologies', 25 | language='ja', 26 | author_name="Contrast Security Japan G.K.", 27 | feed_url='https://contrastsecurity.dev/contrast-documentation-rss/ruby_support_tech_update.xml', 28 | feed_copyright='Copyright 2023 Contrast Security Japan G.K.' 29 | ) 30 | 31 | write_flg = False 32 | item_dict = {} 33 | pubdate = None 34 | for elem in elems: 35 | try: 36 | if elem.parent.name == 'div': 37 | pubdate_str = elem.get("data-time-modified") # November 6, 2023 38 | if pubdate_str: 39 | pubdate = datetime.strptime(pubdate_str, '%B %d, %Y') 40 | #continue 41 | id_str = elem.get("id") 42 | id_hash = hashlib.md5(id_str.encode()).hexdigest() 43 | url = 'https://docs.contrastsecurity.jp/ja/ruby-supported-technologies.html#%s' % id_str 44 | guid = 'https://docs.contrastsecurity.jp/ja/ruby-supported-technologies.html#%s' % id_hash 45 | text_buffer = [] 46 | for elem2 in elem.select('p'): 47 | text_buffer.append(elem2.text) 48 | with open('/files/%s.tmp' % title,'w') as fp: 49 | fp.write('\n'.join(text_buffer)) 50 | before_text = None 51 | try: 52 | with open('/files/%s.txt' % title,'r') as fp: 53 | before_text = fp.readlines() 54 | except FileNotFoundError: 55 | shutil.move('/files/%s.tmp' % title, '/files/%s.txt' % title) 56 | continue 57 | after_text = None 58 | with open('/files/%s.tmp' % title,'r') as fp: 59 | after_text = fp.readlines() 60 | res = difflib.unified_diff(before_text, after_text) 61 | res_str = '\n'.join(res) 62 | if (len(res_str.strip()) > 0): 63 | print('Found diff: ', title) 64 | item_dict[title] = (url, res_str, guid) 65 | shutil.move('/files/%s.tmp' % title, '/files/%s.txt' % title) 66 | except IndexError: 67 | continue 68 | 69 | if pubdate is None: 70 | pubdate = datetime.date.today() 71 | for k, v in item_dict.items(): 72 | feed.add_item(title=k, link=v[0], description=''.join(['

{0}

'.format(s) for s in v[1].splitlines()]), pubdate=pubdate, unique_id=v[2]) 73 | 74 | if len(item_dict) > 0: 75 | str_val = feed.writeString('utf-8') 76 | dom = xml.dom.minidom.parseString(str_val) 77 | with open('/feeds/ruby_support_tech_update.xml','w') as fp: 78 | dom.writexml(fp, encoding='utf-8', newl='\n', indent='', addindent=' ') 79 | 80 | if __name__ == "__main__": 81 | main() 82 | 83 | -------------------------------------------------------------------------------- /work/python_support_tech.py: -------------------------------------------------------------------------------- 1 | import urllib.request as req 2 | from bs4 import BeautifulSoup 3 | import xml.dom.minidom 4 | from django.utils.feedgenerator import Rss201rev2Feed 5 | from datetime import datetime 6 | import locale 7 | import re 8 | import difflib 9 | import shutil 10 | import html 11 | import hashlib 12 | 13 | def main(): 14 | url = 'https://docs.contrastsecurity.jp/ja/python-supported-technologies.html' 15 | res = req.urlopen(url) 16 | soup = BeautifulSoup(res, 'lxml') 17 | elems = soup.select('section.section') 18 | modified_date = soup.select_one('span.formatted-date').text.strip() 19 | title = 'Python' 20 | 21 | feed = Rss201rev2Feed( 22 | title='Python Supported Technologies', 23 | link='https://contrastsecurity.dev/contrast-documentation-rss', 24 | description='Python Supported Technologies', 25 | language='ja', 26 | author_name="Contrast Security Japan G.K.", 27 | feed_url='https://contrastsecurity.dev/contrast-documentation-rss/python_support_tech_update.xml', 28 | feed_copyright='Copyright 2023 Contrast Security Japan G.K.' 29 | ) 30 | 31 | write_flg = False 32 | item_dict = {} 33 | pubdate = None 34 | for elem in elems: 35 | try: 36 | if elem.parent.name == 'div': 37 | pubdate_str = elem.get("data-time-modified") # November 6, 2023 38 | if pubdate_str: 39 | pubdate = datetime.strptime(pubdate_str, '%B %d, %Y') 40 | #continue 41 | id_str = elem.get("id") 42 | id_hash = hashlib.md5(id_str.encode()).hexdigest() 43 | url = 'https://docs.contrastsecurity.jp/ja/python-supported-technologies.html#%s' % id_str 44 | guid = 'https://docs.contrastsecurity.jp/ja/python-supported-technologies.html#%s' % id_hash 45 | text_buffer = [] 46 | for elem2 in elem.select('p'): 47 | text_buffer.append(elem2.text) 48 | with open('/files/%s.tmp' % title,'w') as fp: 49 | fp.write('\n'.join(text_buffer)) 50 | before_text = None 51 | try: 52 | with open('/files/%s.txt' % title,'r') as fp: 53 | before_text = fp.readlines() 54 | except FileNotFoundError: 55 | shutil.move('/files/%s.tmp' % title, '/files/%s.txt' % title) 56 | continue 57 | after_text = None 58 | with open('/files/%s.tmp' % title,'r') as fp: 59 | after_text = fp.readlines() 60 | res = difflib.unified_diff(before_text, after_text) 61 | res_str = '\n'.join(res) 62 | if (len(res_str.strip()) > 0): 63 | print('Found diff: ', title) 64 | item_dict[title] = (url, res_str, guid) 65 | shutil.move('/files/%s.tmp' % title, '/files/%s.txt' % title) 66 | except IndexError: 67 | continue 68 | 69 | if pubdate is None: 70 | pubdate = datetime.date.today() 71 | for k, v in item_dict.items(): 72 | feed.add_item(title=k, link=v[0], description=''.join(['

{0}

'.format(s) for s in v[1].splitlines()]), pubdate=pubdate, unique_id=v[2]) 73 | 74 | if len(item_dict) > 0: 75 | str_val = feed.writeString('utf-8') 76 | dom = xml.dom.minidom.parseString(str_val) 77 | with open('/feeds/python_support_tech_update.xml','w') as fp: 78 | dom.writexml(fp, encoding='utf-8', newl='\n', indent='', addindent=' ') 79 | 80 | if __name__ == "__main__": 81 | main() 82 | 83 | -------------------------------------------------------------------------------- /work/nodejs_support_tech.py: -------------------------------------------------------------------------------- 1 | import urllib.request as req 2 | from bs4 import BeautifulSoup 3 | import xml.dom.minidom 4 | from django.utils.feedgenerator import Rss201rev2Feed 5 | from datetime import datetime 6 | import locale 7 | import re 8 | import difflib 9 | import shutil 10 | import html 11 | import hashlib 12 | 13 | def main(): 14 | url = 'https://docs.contrastsecurity.jp/ja/node-js-supported-technologies.html' 15 | res = req.urlopen(url) 16 | soup = BeautifulSoup(res, 'lxml') 17 | elems = soup.select('section.section') 18 | modified_date = soup.select_one('span.formatted-date').text.strip() 19 | title = 'Nodejs' 20 | 21 | feed = Rss201rev2Feed( 22 | title='Node.js Supported Technologies', 23 | link='https://contrastsecurity.dev/contrast-documentation-rss', 24 | description='Node.js Supported Technologies', 25 | language='ja', 26 | author_name="Contrast Security Japan G.K.", 27 | feed_url='https://contrastsecurity.dev/contrast-documentation-rss/nodejs_support_tech_update.xml', 28 | feed_copyright='Copyright 2023 Contrast Security Japan G.K.' 29 | ) 30 | 31 | write_flg = False 32 | item_dict = {} 33 | pubdate = None 34 | for elem in elems: 35 | try: 36 | if elem.parent.name == 'div': 37 | pubdate_str = elem.get("data-time-modified") # November 6, 2023 38 | if pubdate_str: 39 | pubdate = datetime.strptime(pubdate_str, '%B %d, %Y') 40 | #continue 41 | id_str = elem.get("id") 42 | id_hash = hashlib.md5(id_str.encode()).hexdigest() 43 | url = 'https://docs.contrastsecurity.jp/ja/node-js-supported-technologies.html#%s' % id_str 44 | guid = 'https://docs.contrastsecurity.jp/ja/node-js-supported-technologies.html#%s' % id_hash 45 | text_buffer = [] 46 | for elem2 in elem.select('p'): 47 | text_buffer.append(elem2.text) 48 | with open('/files/%s.tmp' % title,'w') as fp: 49 | fp.write('\n'.join(text_buffer)) 50 | before_text = None 51 | try: 52 | with open('/files/%s.txt' % title,'r') as fp: 53 | before_text = fp.readlines() 54 | except FileNotFoundError: 55 | shutil.move('/files/%s.tmp' % title, '/files/%s.txt' % title) 56 | continue 57 | after_text = None 58 | with open('/files/%s.tmp' % title,'r') as fp: 59 | after_text = fp.readlines() 60 | res = difflib.unified_diff(before_text, after_text) 61 | res_str = '\n'.join(res) 62 | if (len(res_str.strip()) > 0): 63 | print('Found diff: ', title) 64 | item_dict[title] = (url, res_str, guid) 65 | shutil.move('/files/%s.tmp' % title, '/files/%s.txt' % title) 66 | except IndexError: 67 | continue 68 | 69 | if pubdate is None: 70 | pubdate = datetime.date.today() 71 | for k, v in item_dict.items(): 72 | feed.add_item(title=k, link=v[0], description=''.join(['

{0}

'.format(s) for s in v[1].splitlines()]), pubdate=pubdate, unique_id=v[2]) 73 | 74 | if len(item_dict) > 0: 75 | str_val = feed.writeString('utf-8') 76 | dom = xml.dom.minidom.parseString(str_val) 77 | with open('/feeds/nodejs_support_tech_update.xml','w') as fp: 78 | dom.writexml(fp, encoding='utf-8', newl='\n', indent='', addindent=' ') 79 | 80 | if __name__ == "__main__": 81 | main() 82 | 83 | -------------------------------------------------------------------------------- /work/java_support_tech.py: -------------------------------------------------------------------------------- 1 | import urllib.request as req 2 | from bs4 import BeautifulSoup 3 | import xml.dom.minidom 4 | from django.utils.feedgenerator import Rss201rev2Feed 5 | from datetime import datetime as dt 6 | import locale 7 | import re 8 | import difflib 9 | import shutil 10 | import html 11 | import hashlib 12 | 13 | def main(): 14 | url = 'https://docs.contrastsecurity.jp/ja/java-supported-technologies.html' 15 | res = req.urlopen(url) 16 | soup = BeautifulSoup(res, 'lxml') 17 | elems = soup.select('section.section') 18 | modified_date = soup.select_one('span.formatted-date').text.strip() 19 | 20 | feed = Rss201rev2Feed( 21 | title='Java Supported Technologies', 22 | link='https://contrastsecurity.dev/contrast-documentation-rss', 23 | description='Java Supported Technologies', 24 | language='ja', 25 | author_name="Contrast Security Japan G.K.", 26 | feed_url='https://contrastsecurity.dev/contrast-documentation-rss/java_support_tech_update.xml', 27 | feed_copyright='Copyright 2023 Contrast Security Japan G.K.' 28 | ) 29 | 30 | write_flg = False 31 | item_dict = {} 32 | pubdate = None 33 | for elem in elems: 34 | try: 35 | if elem.parent.name == 'div': 36 | pubdate_str = elem.get("data-time-modified") # November 6, 2023 37 | if pubdate_str: 38 | pubdate = dt.strptime(pubdate_str, '%B %d, %Y') 39 | continue 40 | id_str = elem.get("id") 41 | id_hash = hashlib.md5(id_str.encode()).hexdigest() 42 | url = 'https://docs.contrastsecurity.jp/ja/java-supported-technologies.html#%s' % id_str 43 | guid = 'https://docs.contrastsecurity.jp/ja/java-supported-technologies.html#%s' % id_hash 44 | title = elem.select_one('h2.title').text 45 | text_buffer = [] 46 | for elem2 in elem.select('p'): 47 | text_buffer.append(elem2.text) 48 | with open('/files/%s.tmp' % title,'w') as fp: 49 | fp.write('\n'.join(text_buffer)) 50 | before_text = None 51 | try: 52 | with open('/files/%s.txt' % title,'r') as fp: 53 | before_text = fp.readlines() 54 | except FileNotFoundError: 55 | shutil.move('/files/%s.tmp' % title, '/files/%s.txt' % title) 56 | continue 57 | after_text = None 58 | with open('/files/%s.tmp' % title,'r') as fp: 59 | after_text = fp.readlines() 60 | res = difflib.unified_diff(before_text, after_text) 61 | res_str = '\n'.join(res) 62 | if (len(res_str.strip()) > 0): 63 | print('Found diff: ', title) 64 | item_dict[title] = (url, res_str, guid) 65 | shutil.move('/files/%s.tmp' % title, '/files/%s.txt' % title) 66 | except IndexError: 67 | continue 68 | 69 | now_for_pub = dt.today().replace(second=0, microsecond=0) 70 | for k, v in item_dict.items(): 71 | feed.add_item(title=k, link=v[0], description=''.join(['

{0}

'.format(s) for s in v[1].splitlines()]), pubdate=now_for_pub, unique_id=v[2]) 72 | 73 | if len(item_dict) > 0: 74 | str_val = feed.writeString('utf-8') 75 | dom = xml.dom.minidom.parseString(str_val) 76 | with open('/feeds/java_support_tech_update.xml','w') as fp: 77 | dom.writexml(fp, encoding='utf-8', newl='\n', indent='', addindent=' ') 78 | 79 | if __name__ == "__main__": 80 | main() 81 | 82 | -------------------------------------------------------------------------------- /work/dotnet_core_support_tech.py: -------------------------------------------------------------------------------- 1 | import urllib.request as req 2 | from bs4 import BeautifulSoup 3 | import xml.dom.minidom 4 | from django.utils.feedgenerator import Rss201rev2Feed 5 | from datetime import datetime 6 | import locale 7 | import re 8 | import difflib 9 | import shutil 10 | import html 11 | import hashlib 12 | 13 | def main(): 14 | url = 'https://docs.contrastsecurity.jp/ja/-net-core-supported-technologies.html' 15 | res = req.urlopen(url) 16 | soup = BeautifulSoup(res, 'lxml') 17 | elems = soup.select('section.section') 18 | modified_date = soup.select_one('span.formatted-date').text.strip() 19 | title = 'DotNetCore' 20 | 21 | feed = Rss201rev2Feed( 22 | title='.NET Core Supported Technologies', 23 | link='https://contrastsecurity.dev/contrast-documentation-rss', 24 | description='.NET Core Supported Technologies', 25 | language='ja', 26 | author_name="Contrast Security Japan G.K.", 27 | feed_url='https://contrastsecurity.dev/contrast-documentation-rss/dotnet_core_support_tech_update.xml', 28 | feed_copyright='Copyright 2023 Contrast Security Japan G.K.' 29 | ) 30 | 31 | write_flg = False 32 | item_dict = {} 33 | pubdate = None 34 | for elem in elems: 35 | try: 36 | if elem.parent.name == 'div': 37 | pubdate_str = elem.get("data-time-modified") # November 6, 2023 38 | if pubdate_str: 39 | pubdate = datetime.strptime(pubdate_str, '%B %d, %Y') 40 | #continue 41 | id_str = elem.get("id") 42 | id_hash = hashlib.md5(id_str.encode()).hexdigest() 43 | url = 'https://docs.contrastsecurity.jp/ja/-net-core-supported-technologies.html#%s' % id_str 44 | guid = 'https://docs.contrastsecurity.jp/ja/-net-core-supported-technologies.html#%s' % id_hash 45 | text_buffer = [] 46 | for elem2 in elem.select('p'): 47 | text_buffer.append(elem2.text) 48 | with open('/files/%s.tmp' % title,'w') as fp: 49 | fp.write('\n'.join(text_buffer)) 50 | before_text = None 51 | try: 52 | with open('/files/%s.txt' % title,'r') as fp: 53 | before_text = fp.readlines() 54 | except FileNotFoundError: 55 | shutil.move('/files/%s.tmp' % title, '/files/%s.txt' % title) 56 | continue 57 | after_text = None 58 | with open('/files/%s.tmp' % title,'r') as fp: 59 | after_text = fp.readlines() 60 | res = difflib.unified_diff(before_text, after_text) 61 | res_str = '\n'.join(res) 62 | if (len(res_str.strip()) > 0): 63 | print('Found diff: ', title) 64 | item_dict[title] = (url, res_str, guid) 65 | shutil.move('/files/%s.tmp' % title, '/files/%s.txt' % title) 66 | except IndexError: 67 | continue 68 | 69 | if pubdate is None: 70 | pubdate = datetime.date.today() 71 | for k, v in item_dict.items(): 72 | feed.add_item(title=k, link=v[0], description=''.join(['

{0}

'.format(s) for s in v[1].splitlines()]), pubdate=pubdate, unique_id=v[2]) 73 | 74 | if len(item_dict) > 0: 75 | str_val = feed.writeString('utf-8') 76 | dom = xml.dom.minidom.parseString(str_val) 77 | with open('/feeds/dotnet_core_support_tech_update.xml','w') as fp: 78 | dom.writexml(fp, encoding='utf-8', newl='\n', indent='', addindent=' ') 79 | 80 | if __name__ == "__main__": 81 | main() 82 | 83 | -------------------------------------------------------------------------------- /work/dotnet_framework_support_tech.py: -------------------------------------------------------------------------------- 1 | import urllib.request as req 2 | from bs4 import BeautifulSoup 3 | import xml.dom.minidom 4 | from django.utils.feedgenerator import Rss201rev2Feed 5 | from datetime import datetime 6 | import locale 7 | import re 8 | import difflib 9 | import shutil 10 | import html 11 | import hashlib 12 | 13 | def main(): 14 | url = 'https://docs.contrastsecurity.jp/ja/-net-framework-supported-technologies.html' 15 | res = req.urlopen(url) 16 | soup = BeautifulSoup(res, 'lxml') 17 | elems = soup.select('section.section') 18 | modified_date = soup.select_one('span.formatted-date').text.strip() 19 | title = 'DotNetFramework' 20 | 21 | feed = Rss201rev2Feed( 22 | title='.NET Framework Supported Technologies', 23 | link='https://contrastsecurity.dev/contrast-documentation-rss', 24 | description='.NET Framework Supported Technologies', 25 | language='ja', 26 | author_name="Contrast Security Japan G.K.", 27 | feed_url='https://contrastsecurity.dev/contrast-documentation-rss/dotnet_framework_support_tech_update.xml', 28 | feed_copyright='Copyright 2023 Contrast Security Japan G.K.' 29 | ) 30 | 31 | write_flg = False 32 | item_dict = {} 33 | pubdate = None 34 | for elem in elems: 35 | try: 36 | if elem.parent.name == 'div': 37 | pubdate_str = elem.get("data-time-modified") # November 6, 2023 38 | if pubdate_str: 39 | pubdate = datetime.strptime(pubdate_str, '%B %d, %Y') 40 | #continue 41 | id_str = elem.get("id") 42 | id_hash = hashlib.md5(id_str.encode()).hexdigest() 43 | url = 'https://docs.contrastsecurity.jp/ja/-net-framework-supported-technologies.html#%s' % id_str 44 | guid = 'https://docs.contrastsecurity.jp/ja/-net-framework-supported-technologies.html#%s' % id_hash 45 | text_buffer = [] 46 | for elem2 in elem.select('p'): 47 | text_buffer.append(elem2.text) 48 | with open('/files/%s.tmp' % title,'w') as fp: 49 | fp.write('\n'.join(text_buffer)) 50 | before_text = None 51 | try: 52 | with open('/files/%s.txt' % title,'r') as fp: 53 | before_text = fp.readlines() 54 | except FileNotFoundError: 55 | shutil.move('/files/%s.tmp' % title, '/files/%s.txt' % title) 56 | continue 57 | after_text = None 58 | with open('/files/%s.tmp' % title,'r') as fp: 59 | after_text = fp.readlines() 60 | res = difflib.unified_diff(before_text, after_text) 61 | res_str = '\n'.join(res) 62 | if (len(res_str.strip()) > 0): 63 | print('Found diff: ', title) 64 | item_dict[title] = (url, res_str, guid) 65 | shutil.move('/files/%s.tmp' % title, '/files/%s.txt' % title) 66 | except IndexError: 67 | continue 68 | 69 | if pubdate is None: 70 | pubdate = datetime.date.today() 71 | for k, v in item_dict.items(): 72 | feed.add_item(title=k, link=v[0], description=''.join(['

{0}

'.format(s) for s in v[1].splitlines()]), pubdate=pubdate, unique_id=v[2]) 73 | 74 | if len(item_dict) > 0: 75 | str_val = feed.writeString('utf-8') 76 | dom = xml.dom.minidom.parseString(str_val) 77 | with open('/feeds/dotnet_framework_support_tech_update.xml','w') as fp: 78 | dom.writexml(fp, encoding='utf-8', newl='\n', indent='', addindent=' ') 79 | 80 | if __name__ == "__main__": 81 | main() 82 | 83 | -------------------------------------------------------------------------------- /feeds/index.html: -------------------------------------------------------------------------------- 1 |

リリース情報

2 | https://docs.contrastsecurity.jp/ja/release.html 3 |
4 |

RSS feed

5 |

Contrast

6 | Contrast Release Note(SaaS)
7 | https://contrastsecurity.dev/contrast-documentation-rss/contrast_rlsnote_saas.xml
8 | Contrast Release Note(On-premises)
9 | https://contrastsecurity.dev/contrast-documentation-rss/contrast_rlsnote_eop.xml 10 |
11 |

.NET Core

12 | .NET Core Agent Release Note
13 | https://contrastsecurity.dev/contrast-documentation-rss/dotnet_core_rlsnote.xml
14 | .NET Core Supported Technologies
15 | https://contrastsecurity.dev/contrast-documentation-rss/dotnet_core_support_tech_update.xml 16 |
17 |

.NET Framework

18 | .NET Framework Agent Release Note
19 | https://contrastsecurity.dev/contrast-documentation-rss/dotnet_framework_rlsnote.xml
20 | .NET Framework Supported Technologies
21 | https://contrastsecurity.dev/contrast-documentation-rss/dotnet_framework_support_tech_update.xml 22 |
23 |

Go

24 | Go Agent Release Note
25 | https://contrastsecurity.dev/contrast-documentation-rss/go_rlsnote.xml
26 | Go Supported Technologies
27 | https://contrastsecurity.dev/contrast-documentation-rss/go_support_tech_update.xml 28 |
29 |

Java

30 | Java Agent Release Note
31 | https://contrastsecurity.dev/contrast-documentation-rss/java_rlsnote.xml
32 | Java Supported Technologies
33 | https://contrastsecurity.dev/contrast-documentation-rss/java_support_tech_update.xml 34 |
35 |

NodeJS

36 | Node.js Agent Release Note
37 | https://contrastsecurity.dev/contrast-documentation-rss/nodejs_rlsnote.xml
38 | Node.js Agent Beta Release Note
39 | https://contrastsecurity.dev/contrast-documentation-rss/nodejs_beta_rlsnote.xml
40 | Node.js Agent Protect Release Note
41 | https://contrastsecurity.dev/contrast-documentation-rss/nodejs_protect_rlsnote.xml
42 | Node.js Supported Technologies
43 | https://contrastsecurity.dev/contrast-documentation-rss/nodejs_support_tech_update.xml 44 |
45 |

PHP

46 | PHP Agent Release Note
47 | https://contrastsecurity.dev/contrast-documentation-rss/php_rlsnote.xml
48 | PHP Supported Technologies
49 | https://contrastsecurity.dev/contrast-documentation-rss/php_support_tech_update.xml 50 |
51 |

Python

52 | Python Agent Release Note
53 | https://contrastsecurity.dev/contrast-documentation-rss/python_rlsnote.xml
54 | Python Supported Technologies
55 | https://contrastsecurity.dev/contrast-documentation-rss/python_support_tech_update.xml 56 |
57 |

Ruby

58 | Ruby Agent Release Note
59 | https://contrastsecurity.dev/contrast-documentation-rss/ruby_rlsnote.xml
60 | Ruby Supported Technologies
61 | https://contrastsecurity.dev/contrast-documentation-rss/ruby_support_tech_update.xml 62 |
63 |

End Of Agent Support

64 | https://contrastsecurity.dev/contrast-documentation-rss/end_of_support.xml 65 | 66 | -------------------------------------------------------------------------------- /work/agent_end_support_chk.py: -------------------------------------------------------------------------------- 1 | import urllib.request as req 2 | from bs4 import BeautifulSoup 3 | import xml.dom.minidom 4 | from django.utils.feedgenerator import Rss201rev2Feed 5 | from datetime import datetime as dt 6 | from dateutil.relativedelta import relativedelta 7 | import datetime 8 | import locale 9 | import html 10 | import hashlib 11 | import os 12 | import json 13 | import time 14 | import re 15 | 16 | CONTRAST_AGENT_INFOS = [ 17 | { 18 | 'language': '.NET Core', 19 | 'doc_url': 'https://docs.contrastsecurity.jp/ja/-net-core-agent-release-notes-and-archive.html', 20 | 'check_word': '.net', 21 | }, { 22 | 'language': '.NET Framework', 23 | 'doc_url': 'https://docs.contrastsecurity.jp/ja/-net-framework-agent-release-notes-and-archive.html', 24 | 'check_word': '.net', 25 | }, { 26 | 'language': 'Go', 27 | 'doc_url': 'https://docs.contrastsecurity.jp/ja/go-agent-release-notes-and-archive.html', 28 | 'check_word': 'go', 29 | }, { 30 | 'language': 'Java', 31 | 'doc_url': 'https://docs.contrastsecurity.jp/ja/java-agent-release-notes-and-archive.html', 32 | 'check_word': 'java', 33 | }, { 34 | 'language': 'NodeJS', 35 | 'doc_url': 'https://docs.contrastsecurity.jp/ja/node-js-agent-release-notes-and-archive.html', 36 | 'check_word': 'node', 37 | }, { 38 | 'language': 'PHP', 39 | 'doc_url': 'https://docs.contrastsecurity.jp/ja/php-agent-release-notes-and-archive.html', 40 | 'check_word': 'php', 41 | }, { 42 | 'language': 'Python', 43 | 'doc_url': 'https://docs.contrastsecurity.jp/ja/python-agent-release-notes-and-archive.html', 44 | 'check_word': 'python', 45 | }, { 46 | 'language': 'Ruby', 47 | 'doc_url': 'https://docs.contrastsecurity.jp/ja/ruby-agent-release-notes-and-archive.html', 48 | 'check_word': 'ruby', 49 | }, 50 | ] 51 | 52 | def main(): 53 | locale.setlocale(locale.LC_TIME, "C") 54 | path = '/files/agent_rlsdate.json' 55 | versions_dict = {} 56 | if os.path.isfile(path): 57 | with open(path) as f: 58 | versions_dict = json.load(f) 59 | 60 | for agent_info in CONTRAST_AGENT_INFOS: 61 | #print(agent_info['language'], agent_info['doc_url']) 62 | res = req.urlopen(agent_info['doc_url']) 63 | soup = BeautifulSoup(res, 'lxml') 64 | elems = soup.select('section.section.accordion') 65 | for elem in elems: 66 | try: 67 | id_str = elem.get("id") 68 | pubdate_str = elem.get("data-time-modified") # November 6, 2023 69 | pubdate = None 70 | if pubdate_str: 71 | pubdate = dt.strptime(pubdate_str, '%B %d, %Y') 72 | title = elem.select('h3.title')[0].text.strip() 73 | if not title.lower().startswith(agent_info['check_word']): 74 | continue 75 | desc_buffer = [] 76 | for elem2 in elem.select('p'): 77 | if elem2.parent.name == 'li': 78 | desc_buffer.append('・%s' % elem2.text) 79 | else: 80 | desc_buffer.append('%s' % elem2.text) 81 | id_hash = hashlib.md5(id_str.encode()).hexdigest() 82 | description = ''.join(desc_buffer) 83 | rls_date = None 84 | if 'リリース日' in description: 85 | m = re.search('リリース日[^2]+([0-9]{4})年([0-9]{1,2})月([0-9]{1,2})日', description) 86 | if m is None: 87 | continue 88 | rls_date = dt(int(m.group(1)), int(m.group(2)), int(m.group(3))) 89 | elif 'Release date' in description: 90 | m = re.search('Release date[^A-Z]+(([A-Za-z]+) ([0-9]{1,2}), ([0-9]{4}))', description) 91 | if m is None: 92 | continue 93 | rls_date = dt.strptime(m.group(1), '%B %d, %Y') 94 | if rls_date: 95 | versions_dict[title] = (rls_date.strftime('%Y%m%d%H%M%S'), agent_info['doc_url'], id_hash) 96 | except IndexError: 97 | continue 98 | time.sleep(1) 99 | 100 | feed = Rss201rev2Feed( 101 | title='End of Agent support', 102 | link='https://contrastsecurity.dev/contrast-documentation-rss', 103 | description='End Of Agent Support', 104 | language='ja', 105 | author_name="Contrast Security Japan G.K.", 106 | feed_url='https://contrastsecurity.dev/contrast-documentation-rss/end_of_support.xml', 107 | feed_copyright='Copyright 2024 Contrast Security Japan G.K.' 108 | ) 109 | 110 | today = dt.today().replace(hour=0, minute=0, second=0, microsecond=0) 111 | env_today = os.getenv('TODAY') 112 | if env_today: 113 | today = dt.strptime(env_today, '%Y-%m-%d').replace(hour=0, minute=0, second=0, microsecond=0) 114 | print('using env.TODAY %s' % today) 115 | item_dict = {} 116 | for index, (title, data_tuple) in enumerate(versions_dict.items()): 117 | rls_date = dt.strptime(data_tuple[0], '%Y%m%d%H%M%S') 118 | date_end_of_support = rls_date + relativedelta(years=1) 119 | date_end_of_support = date_end_of_support - datetime.timedelta(days=1) 120 | date_before_30days = date_end_of_support - datetime.timedelta(days=30) 121 | #print(title, rls_date, today, date_end_of_support, date_before_30days) 122 | if today == date_before_30days: 123 | item_dict[title] = (data_tuple[1], '%s エージェントのサポート終了から30日前です。' % title, data_tuple[2], index) 124 | if today == date_end_of_support: 125 | item_dict[title] = (data_tuple[1], '%s エージェントのサポート終了日となります。' % title, data_tuple[2], index) 126 | 127 | now_for_pub = dt.today().replace(second=0, microsecond=0) 128 | sorted_keys = sorted(item_dict.keys(), key=lambda x: item_dict[x][3], reverse=True) 129 | for k in sorted_keys: # e.g. ['Java 4.12', 'Java 4.12.1'] 130 | v = item_dict[k] 131 | feed.add_item(title=k, link=v[0], description=''.join(['

{0}

'.format(s) for s in v[1].splitlines()]), pubdate=now_for_pub, unique_id=v[2]) 132 | str_val = feed.writeString('utf-8') 133 | dom = xml.dom.minidom.parseString(str_val) 134 | with open('/feeds/end_of_support.xml','w') as fp: 135 | dom.writexml(fp, encoding='utf-8', newl='\n', indent='', addindent=' ') 136 | 137 | with open(path, 'w') as f: 138 | json.dump(versions_dict, f, indent=4) 139 | 140 | if __name__ == "__main__": 141 | main() 142 | 143 | --------------------------------------------------------------------------------