From e5cfbab511a408092617246dc8e257c0742eb59d Mon Sep 17 00:00:00 2001 From: Viachaslau Tyshkavets Date: Fri, 9 Jan 2026 11:08:24 +0400 Subject: [PATCH 01/18] chore(ci): add GitHub Actions workflow for Rails smoke test --- .github/workflows/ci.yml | 101 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..e796ce8 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,101 @@ +name: ci + +on: + push: + branches: + - main + pull_request: + +jobs: + test: + runs-on: ubuntu-latest + services: + postgres: + image: postgres:9.6 + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: blog_development + ports: + - 5432:5432 + options: >- + --health-cmd "pg_isready -U postgres" + --health-interval 5s + --health-timeout 5s + --health-retries 10 + env: + PGHOST: localhost + PGPORT: 5432 + PGUSER: postgres + PGPASSWORD: postgres + PGDATABASE: blog_development + DATABASE_URL: postgres://postgres:postgres@localhost:5432/blog_development + steps: + - uses: actions/checkout@v4 + + - uses: ruby/setup-ruby@v1 + with: + ruby-version: "2.3.3" + + - name: Install system deps + run: | + sudo apt-get update + sudo apt-get install -y --no-install-recommends \ + build-essential \ + libpq-dev \ + libxml2-dev \ + libxslt1-dev \ + nodejs \ + zlib1g-dev + + - name: Install bundler + run: gem install bundler -v 1.10.6 + + - name: Configure bundler for nokogiri + run: bundle config build.nokogiri --use-system-libraries + + - name: Install gems + run: bundle install + + - name: Wait for postgres + run: | + for i in $(seq 1 30); do + bundle exec ruby -e "require 'pg'; PG.connect(host: ENV['PGHOST'], port: ENV['PGPORT'].to_i, dbname: ENV['PGDATABASE'], user: ENV['PGUSER'], password: ENV['PGPASSWORD']);" && exit 0 + sleep 2 + done + exit 1 + + - name: Setup database + run: bundle exec rake db:create db:migrate db:seed + + - name: Start server + run: | + bundle exec rails server -b 0.0.0.0 -p 3000 >rails.log 2>&1 & + + - name: Wait for server readiness + run: | + READY=0 + for i in $(seq 1 30); do + echo "Attempt ${i}/30: checking http://localhost:3000" + if curl -sSfL http://localhost:3000 >/dev/null; then + echo "Server responded successfully on attempt ${i}." + READY=1 + break + fi + echo "Server still starting up, waiting 2s before retry." + sleep 2 + done + if [ "$READY" -ne 1 ]; then + echo "Server failed to start" + tail -n 200 rails.log || true + exit 1 + fi + echo "Server is ready; last 200 lines of rails.log:" + tail -n 200 rails.log || true + + - name: Check homepage + run: | + if ! curl -sSfL http://localhost:3000 | grep -F "Home"; then + echo "Homepage check failed" + exit 1 + fi \ No newline at end of file From 890c6d129c245fe4a9d01323c0fa175e1fe6db1e Mon Sep 17 00:00:00 2001 From: Viachaslau Tyshkavets Date: Fri, 9 Jan 2026 11:57:29 +0400 Subject: [PATCH 02/18] chore(ci): run test job in container mode for legacy Ruby compatibility --- .github/workflows/ci.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e796ce8..7f4b2e5 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,6 +9,8 @@ on: jobs: test: runs-on: ubuntu-latest + container: + image: ruby:2.3 services: postgres: image: postgres:9.6 @@ -39,8 +41,8 @@ jobs: - name: Install system deps run: | - sudo apt-get update - sudo apt-get install -y --no-install-recommends \ + apt-get update + apt-get install -y --no-install-recommends \ build-essential \ libpq-dev \ libxml2-dev \ From 5408c9b3915700c342680eb7a8624b78bf0da1df Mon Sep 17 00:00:00 2001 From: Viachaslau Tyshkavets Date: Fri, 9 Jan 2026 12:02:07 +0400 Subject: [PATCH 03/18] chore(ci): switch job image to buildpack-deps:buster for native build tooling --- .github/workflows/ci.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7f4b2e5..fa7fe4b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -10,7 +10,7 @@ jobs: test: runs-on: ubuntu-latest container: - image: ruby:2.3 + image: buildpack-deps:buster services: postgres: image: postgres:9.6 From 0f619cceea5ad433476524d9951647df4bcecbfa Mon Sep 17 00:00:00 2001 From: Viachaslau Tyshkavets Date: Fri, 9 Jan 2026 12:41:19 +0400 Subject: [PATCH 04/18] chore(ci): build Ruby 2.3.3 from source via ruby-build --- .github/workflows/ci.yml | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index fa7fe4b..3012e2a 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,20 +35,30 @@ jobs: steps: - uses: actions/checkout@v4 - - uses: ruby/setup-ruby@v1 - with: - ruby-version: "2.3.3" - - name: Install system deps run: | apt-get update apt-get install -y --no-install-recommends \ - build-essential \ - libpq-dev \ - libxml2-dev \ - libxslt1-dev \ - nodejs \ - zlib1g-dev + build-essential \ + libffi-dev \ + libgdbm-dev \ + libpq-dev \ + libreadline-dev \ + libssl-dev \ + libxml2-dev \ + libxslt1-dev \ + nodejs \ + libyaml-dev \ + zlib1g-dev + + - name: Install Ruby 2.3.3 + env: + RUBY_PREFIX: /opt/ruby-2.3.3 + run: | + git clone --depth=1 https://github.com/rbenv/ruby-build.git /tmp/ruby-build + /tmp/ruby-build/install.sh + ruby-build 2.3.3 "$RUBY_PREFIX" + echo "$RUBY_PREFIX/bin" >> "$GITHUB_PATH" - name: Install bundler run: gem install bundler -v 1.10.6 From 4059255f1802de12a9155d0e375874b59682a3cb Mon Sep 17 00:00:00 2001 From: Viachaslau Tyshkavets Date: Fri, 9 Jan 2026 12:46:25 +0400 Subject: [PATCH 05/18] chore(ci): use Debian archive mirrors for EOL buster apt repos --- .github/workflows/ci.yml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3012e2a..92c905e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -35,10 +35,16 @@ jobs: steps: - uses: actions/checkout@v4 + - name: Point apt to Debian archive + run: | + sed -i 's|deb.debian.org/debian|archive.debian.org/debian|g' /etc/apt/sources.list + sed -i 's|security.debian.org/debian-security|archive.debian.org/debian-security|g' /etc/apt/sources.list + sed -i '/buster-updates/d' /etc/apt/sources.list + - name: Install system deps run: | - apt-get update - apt-get install -y --no-install-recommends \ + apt-get -o Acquire::Check-Valid-Until=false -o Acquire::AllowInsecureRepositories=true update + apt-get -o Acquire::Check-Valid-Until=false -o Acquire::AllowInsecureRepositories=true install -y --no-install-recommends \ build-essential \ libffi-dev \ libgdbm-dev \ From b4a6ba1ad9f84690acb43bd7c73fb079b0101779 Mon Sep 17 00:00:00 2001 From: Viachaslau Tyshkavets Date: Fri, 9 Jan 2026 12:56:41 +0400 Subject: [PATCH 06/18] chore(ci): fix Postgres host and readiness checks for container-mode networking --- .github/workflows/ci.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 92c905e..720a590 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -21,17 +21,18 @@ jobs: ports: - 5432:5432 options: >- + --name postgres --health-cmd "pg_isready -U postgres" --health-interval 5s --health-timeout 5s --health-retries 10 env: - PGHOST: localhost + PGHOST: postgres PGPORT: 5432 PGUSER: postgres PGPASSWORD: postgres PGDATABASE: blog_development - DATABASE_URL: postgres://postgres:postgres@localhost:5432/blog_development + DATABASE_URL: postgres://postgres:postgres@postgres:5432/blog_development steps: - uses: actions/checkout@v4 @@ -78,10 +79,10 @@ jobs: - name: Wait for postgres run: | for i in $(seq 1 30); do - bundle exec ruby -e "require 'pg'; PG.connect(host: ENV['PGHOST'], port: ENV['PGPORT'].to_i, dbname: ENV['PGDATABASE'], user: ENV['PGUSER'], password: ENV['PGPASSWORD']);" && exit 0 + pg_isready -h "$PGHOST" -p "$PGPORT" -d "$PGDATABASE" && break sleep 2 done - exit 1 + bundle exec ruby -e "require 'pg'; PG.connect(host: ENV['PGHOST'], port: ENV['PGPORT'].to_i, dbname: ENV['PGDATABASE'], user: ENV['PGUSER'], password: ENV['PGPASSWORD']);" - name: Setup database run: bundle exec rake db:create db:migrate db:seed From f821f91e353d363d45d73b8b692ba566a00aaeda Mon Sep 17 00:00:00 2001 From: Viachaslau Tyshkavets Date: Mon, 16 Feb 2026 11:16:03 +0400 Subject: [PATCH 07/18] chore(ci): add install postgresql-client --- .github/workflows/ci.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 720a590..4620fbf 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -54,6 +54,7 @@ jobs: libssl-dev \ libxml2-dev \ libxslt1-dev \ + postgresql-client \ nodejs \ libyaml-dev \ zlib1g-dev @@ -117,4 +118,4 @@ jobs: if ! curl -sSfL http://localhost:3000 | grep -F "Home"; then echo "Homepage check failed" exit 1 - fi \ No newline at end of file + fi From d6ab3321c9981a7121e332a96478c3c78238caf7 Mon Sep 17 00:00:00 2001 From: Viachaslau Tyshkavets Date: Mon, 16 Feb 2026 16:46:45 +0400 Subject: [PATCH 08/18] chore(ci): set bash as explicit default shell --- .github/workflows/ci.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 4620fbf..4e2a120 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -11,6 +11,9 @@ jobs: runs-on: ubuntu-latest container: image: buildpack-deps:buster + defaults: + run: + shell: bash services: postgres: image: postgres:9.6 From 6cd4ce48c0d0d724a19d2b18f3fcfe1deb0a4e51 Mon Sep 17 00:00:00 2001 From: Viachaslau Date: Tue, 17 Feb 2026 22:05:20 +0400 Subject: [PATCH 09/18] chore: initialize workflow skip-checks:true --- .brightsec/.gitkeep | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 .brightsec/.gitkeep diff --git a/.brightsec/.gitkeep b/.brightsec/.gitkeep new file mode 100644 index 0000000..e69de29 From a2bac58d49a3e9e8d03a08ddf1e14ee4766e14f8 Mon Sep 17 00:00:00 2001 From: Viachaslau Date: Tue, 17 Feb 2026 22:17:48 +0400 Subject: [PATCH 10/18] ci: temporarily disable workflows while addressing security issues skip-checks:true --- .github/workflows/ci.yml | 124 --------------------------------------- 1 file changed, 124 deletions(-) delete mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml deleted file mode 100644 index 4e2a120..0000000 --- a/.github/workflows/ci.yml +++ /dev/null @@ -1,124 +0,0 @@ -name: ci - -on: - push: - branches: - - main - pull_request: - -jobs: - test: - runs-on: ubuntu-latest - container: - image: buildpack-deps:buster - defaults: - run: - shell: bash - services: - postgres: - image: postgres:9.6 - env: - POSTGRES_USER: postgres - POSTGRES_PASSWORD: postgres - POSTGRES_DB: blog_development - ports: - - 5432:5432 - options: >- - --name postgres - --health-cmd "pg_isready -U postgres" - --health-interval 5s - --health-timeout 5s - --health-retries 10 - env: - PGHOST: postgres - PGPORT: 5432 - PGUSER: postgres - PGPASSWORD: postgres - PGDATABASE: blog_development - DATABASE_URL: postgres://postgres:postgres@postgres:5432/blog_development - steps: - - uses: actions/checkout@v4 - - - name: Point apt to Debian archive - run: | - sed -i 's|deb.debian.org/debian|archive.debian.org/debian|g' /etc/apt/sources.list - sed -i 's|security.debian.org/debian-security|archive.debian.org/debian-security|g' /etc/apt/sources.list - sed -i '/buster-updates/d' /etc/apt/sources.list - - - name: Install system deps - run: | - apt-get -o Acquire::Check-Valid-Until=false -o Acquire::AllowInsecureRepositories=true update - apt-get -o Acquire::Check-Valid-Until=false -o Acquire::AllowInsecureRepositories=true install -y --no-install-recommends \ - build-essential \ - libffi-dev \ - libgdbm-dev \ - libpq-dev \ - libreadline-dev \ - libssl-dev \ - libxml2-dev \ - libxslt1-dev \ - postgresql-client \ - nodejs \ - libyaml-dev \ - zlib1g-dev - - - name: Install Ruby 2.3.3 - env: - RUBY_PREFIX: /opt/ruby-2.3.3 - run: | - git clone --depth=1 https://github.com/rbenv/ruby-build.git /tmp/ruby-build - /tmp/ruby-build/install.sh - ruby-build 2.3.3 "$RUBY_PREFIX" - echo "$RUBY_PREFIX/bin" >> "$GITHUB_PATH" - - - name: Install bundler - run: gem install bundler -v 1.10.6 - - - name: Configure bundler for nokogiri - run: bundle config build.nokogiri --use-system-libraries - - - name: Install gems - run: bundle install - - - name: Wait for postgres - run: | - for i in $(seq 1 30); do - pg_isready -h "$PGHOST" -p "$PGPORT" -d "$PGDATABASE" && break - sleep 2 - done - bundle exec ruby -e "require 'pg'; PG.connect(host: ENV['PGHOST'], port: ENV['PGPORT'].to_i, dbname: ENV['PGDATABASE'], user: ENV['PGUSER'], password: ENV['PGPASSWORD']);" - - - name: Setup database - run: bundle exec rake db:create db:migrate db:seed - - - name: Start server - run: | - bundle exec rails server -b 0.0.0.0 -p 3000 >rails.log 2>&1 & - - - name: Wait for server readiness - run: | - READY=0 - for i in $(seq 1 30); do - echo "Attempt ${i}/30: checking http://localhost:3000" - if curl -sSfL http://localhost:3000 >/dev/null; then - echo "Server responded successfully on attempt ${i}." - READY=1 - break - fi - echo "Server still starting up, waiting 2s before retry." - sleep 2 - done - if [ "$READY" -ne 1 ]; then - echo "Server failed to start" - tail -n 200 rails.log || true - exit 1 - fi - echo "Server is ready; last 200 lines of rails.log:" - tail -n 200 rails.log || true - - - name: Check homepage - run: | - if ! curl -sSfL http://localhost:3000 | grep -F "Home"; then - echo "Homepage check failed" - exit 1 - fi From 5829ae2a4ce7ce0ff2dc500aa297f99ace910bab Mon Sep 17 00:00:00 2001 From: Viachaslau Date: Tue, 17 Feb 2026 22:20:49 +0400 Subject: [PATCH 11/18] test: add auto-generated e2e security tests skip-checks:true --- .brightsec/tests/delete-logout.test.ts | 39 +++++++++++++++ .brightsec/tests/delete-posts-1.test.ts | 40 ++++++++++++++++ .brightsec/tests/delete-users-1-json.test.ts | 39 +++++++++++++++ .brightsec/tests/delete-users-1.test.ts | 39 +++++++++++++++ .brightsec/tests/get-login.test.ts | 39 +++++++++++++++ .brightsec/tests/get-posts-1-edit.test.ts | 39 +++++++++++++++ .brightsec/tests/get-posts-1.test.ts | 39 +++++++++++++++ .brightsec/tests/get-posts-search.test.ts | 39 +++++++++++++++ .brightsec/tests/get-root.test.ts | 39 +++++++++++++++ .brightsec/tests/get-users-1-edit.test.ts | 39 +++++++++++++++ .brightsec/tests/get-users-1-json.test.ts | 40 ++++++++++++++++ .../tests/get-users-1-posts-new.test.ts | 39 +++++++++++++++ .brightsec/tests/get-users-1-posts.test.ts | 39 +++++++++++++++ .brightsec/tests/get-users-1.test.ts | 39 +++++++++++++++ .brightsec/tests/get-users-json.test.ts | 39 +++++++++++++++ .brightsec/tests/get-users-new.test.ts | 39 +++++++++++++++ .brightsec/tests/get-users.test.ts | 39 +++++++++++++++ .brightsec/tests/patch-posts-1.test.ts | 45 +++++++++++++++++ .brightsec/tests/patch-users-123.test.ts | 46 ++++++++++++++++++ .brightsec/tests/post-login.test.ts | 44 +++++++++++++++++ .brightsec/tests/post-users-json.test.ts | 48 +++++++++++++++++++ .brightsec/tests/post-users.test.ts | 48 +++++++++++++++++++ .brightsec/tests/put-posts-1.test.ts | 45 +++++++++++++++++ .brightsec/tests/put-users-123-json.test.ts | 48 +++++++++++++++++++ .brightsec/tests/put-users-123.test.ts | 46 ++++++++++++++++++ 25 files changed, 1035 insertions(+) create mode 100644 .brightsec/tests/delete-logout.test.ts create mode 100644 .brightsec/tests/delete-posts-1.test.ts create mode 100644 .brightsec/tests/delete-users-1-json.test.ts create mode 100644 .brightsec/tests/delete-users-1.test.ts create mode 100644 .brightsec/tests/get-login.test.ts create mode 100644 .brightsec/tests/get-posts-1-edit.test.ts create mode 100644 .brightsec/tests/get-posts-1.test.ts create mode 100644 .brightsec/tests/get-posts-search.test.ts create mode 100644 .brightsec/tests/get-root.test.ts create mode 100644 .brightsec/tests/get-users-1-edit.test.ts create mode 100644 .brightsec/tests/get-users-1-json.test.ts create mode 100644 .brightsec/tests/get-users-1-posts-new.test.ts create mode 100644 .brightsec/tests/get-users-1-posts.test.ts create mode 100644 .brightsec/tests/get-users-1.test.ts create mode 100644 .brightsec/tests/get-users-json.test.ts create mode 100644 .brightsec/tests/get-users-new.test.ts create mode 100644 .brightsec/tests/get-users.test.ts create mode 100644 .brightsec/tests/patch-posts-1.test.ts create mode 100644 .brightsec/tests/patch-users-123.test.ts create mode 100644 .brightsec/tests/post-login.test.ts create mode 100644 .brightsec/tests/post-users-json.test.ts create mode 100644 .brightsec/tests/post-users.test.ts create mode 100644 .brightsec/tests/put-posts-1.test.ts create mode 100644 .brightsec/tests/put-users-123-json.test.ts create mode 100644 .brightsec/tests/put-users-123.test.ts diff --git a/.brightsec/tests/delete-logout.test.ts b/.brightsec/tests/delete-logout.test.ts new file mode 100644 index 0000000..956ee51 --- /dev/null +++ b/.brightsec/tests/delete-logout.test.ts @@ -0,0 +1,39 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('DELETE /logout', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'http_method_fuzzing'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:chore/ci', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.DELETE, + url: `${baseUrl}/logout` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/delete-posts-1.test.ts b/.brightsec/tests/delete-posts-1.test.ts new file mode 100644 index 0000000..82db847 --- /dev/null +++ b/.brightsec/tests/delete-posts-1.test.ts @@ -0,0 +1,40 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('DELETE /posts/1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'bopla', 'id_enumeration'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:chore/ci', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.DELETE, + url: `${baseUrl}/posts/1`, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/delete-users-1-json.test.ts b/.brightsec/tests/delete-users-1-json.test.ts new file mode 100644 index 0000000..92559f5 --- /dev/null +++ b/.brightsec/tests/delete-users-1-json.test.ts @@ -0,0 +1,39 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('DELETE /users/1.json', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'bopla', 'id_enumeration', 'sqli'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:chore/ci', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.DELETE, + url: `${baseUrl}/users/1.json` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/delete-users-1.test.ts b/.brightsec/tests/delete-users-1.test.ts new file mode 100644 index 0000000..7943ee0 --- /dev/null +++ b/.brightsec/tests/delete-users-1.test.ts @@ -0,0 +1,39 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('DELETE /users/1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'bopla', 'id_enumeration', 'sqli'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:chore/ci', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.DELETE, + url: `${baseUrl}/users/1` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-login.test.ts b/.brightsec/tests/get-login.test.ts new file mode 100644 index 0000000..d329249 --- /dev/null +++ b/.brightsec/tests/get-login.test.ts @@ -0,0 +1,39 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /login', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'sqli', 'xss', 'unvalidated_redirect', 'secret_tokens'], + attackParamLocations: [AttackParamLocation.QUERY, AttackParamLocation.HEADER], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:chore/ci', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/login` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-posts-1-edit.test.ts b/.brightsec/tests/get-posts-1-edit.test.ts new file mode 100644 index 0000000..7c08ba1 --- /dev/null +++ b/.brightsec/tests/get-posts-1-edit.test.ts @@ -0,0 +1,39 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /posts/1/edit', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'bopla', 'xss', 'id_enumeration', 'sqli'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:chore/ci', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/posts/1/edit` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-posts-1.test.ts b/.brightsec/tests/get-posts-1.test.ts new file mode 100644 index 0000000..d2622dc --- /dev/null +++ b/.brightsec/tests/get-posts-1.test.ts @@ -0,0 +1,39 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /posts/1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'id_enumeration', 'sqli', 'xss', 'bopla'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:chore/ci', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/posts/1` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-posts-search.test.ts b/.brightsec/tests/get-posts-search.test.ts new file mode 100644 index 0000000..9bc87c4 --- /dev/null +++ b/.brightsec/tests/get-posts-search.test.ts @@ -0,0 +1,39 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /posts/search?search_term=example', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['sqli', 'xss', 'csrf', 'business_constraint_bypass'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:chore/ci', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/posts/search?search_term=example` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-root.test.ts b/.brightsec/tests/get-root.test.ts new file mode 100644 index 0000000..d6b0e6c --- /dev/null +++ b/.brightsec/tests/get-root.test.ts @@ -0,0 +1,39 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['sqli', 'csrf', 'xss', 'bopla'], + attackParamLocations: [AttackParamLocation.PATH, AttackParamLocation.QUERY], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:chore/ci', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-users-1-edit.test.ts b/.brightsec/tests/get-users-1-edit.test.ts new file mode 100644 index 0000000..002e4ba --- /dev/null +++ b/.brightsec/tests/get-users-1-edit.test.ts @@ -0,0 +1,39 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /users/1/edit', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'bopla', 'id_enumeration', 'xss'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:chore/ci', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/users/1/edit` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-users-1-json.test.ts b/.brightsec/tests/get-users-1-json.test.ts new file mode 100644 index 0000000..5b41b23 --- /dev/null +++ b/.brightsec/tests/get-users-1-json.test.ts @@ -0,0 +1,40 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /users/1.json', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['id_enumeration', 'bopla', 'sqli', 'xss'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:chore/ci', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/users/1.json`, + headers: { 'Accept': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-users-1-posts-new.test.ts b/.brightsec/tests/get-users-1-posts-new.test.ts new file mode 100644 index 0000000..45db074 --- /dev/null +++ b/.brightsec/tests/get-users-1-posts-new.test.ts @@ -0,0 +1,39 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /users/1/posts/new', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'xss', 'bopla'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:chore/ci', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/users/1/posts/new` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-users-1-posts.test.ts b/.brightsec/tests/get-users-1-posts.test.ts new file mode 100644 index 0000000..930c8ea --- /dev/null +++ b/.brightsec/tests/get-users-1-posts.test.ts @@ -0,0 +1,39 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /users/1/posts', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'sqli', 'id_enumeration', 'xss', 'bopla'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:chore/ci', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/users/1/posts` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-users-1.test.ts b/.brightsec/tests/get-users-1.test.ts new file mode 100644 index 0000000..98be69f --- /dev/null +++ b/.brightsec/tests/get-users-1.test.ts @@ -0,0 +1,39 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /users/1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['id_enumeration', 'bopla', 'sqli', 'xss', 'csrf'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: "NeuraLegion/ruby-example-app:chore/ci", + databases: ["PostgreSQL"], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/users/1` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-users-json.test.ts b/.brightsec/tests/get-users-json.test.ts new file mode 100644 index 0000000..4dca5fd --- /dev/null +++ b/.brightsec/tests/get-users-json.test.ts @@ -0,0 +1,39 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /users.json', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'id_enumeration', 'improper_asset_management', 'xss'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:chore/ci', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/users.json` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-users-new.test.ts b/.brightsec/tests/get-users-new.test.ts new file mode 100644 index 0000000..b39a3f8 --- /dev/null +++ b/.brightsec/tests/get-users-new.test.ts @@ -0,0 +1,39 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /users/new', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'xss', 'html_injection', 'bopla'], + attackParamLocations: [AttackParamLocation.PATH], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:chore/ci', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/users/new` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/get-users.test.ts b/.brightsec/tests/get-users.test.ts new file mode 100644 index 0000000..10ab3bc --- /dev/null +++ b/.brightsec/tests/get-users.test.ts @@ -0,0 +1,39 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('GET /users', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'id_enumeration', 'improper_asset_management', 'sqli', 'xss'], + attackParamLocations: [AttackParamLocation.QUERY], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:chore/ci', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.GET, + url: `${baseUrl}/users` + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/patch-posts-1.test.ts b/.brightsec/tests/patch-posts-1.test.ts new file mode 100644 index 0000000..7d7b139 --- /dev/null +++ b/.brightsec/tests/patch-posts-1.test.ts @@ -0,0 +1,45 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('PATCH /posts/1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'bopla', 'sqli', 'xss', 'id_enumeration'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:chore/ci', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.PATCH, + url: `${baseUrl}/posts/1`, + body: { + title: 'Updated Title', + content: 'Updated content of the post.', + public: true + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/patch-users-123.test.ts b/.brightsec/tests/patch-users-123.test.ts new file mode 100644 index 0000000..d641873 --- /dev/null +++ b/.brightsec/tests/patch-users-123.test.ts @@ -0,0 +1,46 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('PATCH /users/123', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'csrf', 'sqli', 'xss'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:chore/ci', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.PATCH, + url: `${baseUrl}/users/123.json`, + body: { + email: 'user@example.com', + password: 'securepassword', + password_digest: '$2a$12$KIXQ1Y1rZ1u1u1u1u1u1uO', + admin: false + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-login.test.ts b/.brightsec/tests/post-login.test.ts new file mode 100644 index 0000000..bca2404 --- /dev/null +++ b/.brightsec/tests/post-login.test.ts @@ -0,0 +1,44 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('POST /login', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'sqli', 'xss', 'unvalidated_redirect', 'secret_tokens'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:chore/ci', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/login`, + body: { + email: 'user@example.com', + password: 'securepassword' + }, + headers: { 'Content-Type': 'application/x-www-form-urlencoded' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-users-json.test.ts b/.brightsec/tests/post-users-json.test.ts new file mode 100644 index 0000000..68151ea --- /dev/null +++ b/.brightsec/tests/post-users-json.test.ts @@ -0,0 +1,48 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('POST /users.json', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'bopla', 'sqli', 'xss', 'secret_tokens'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:chore/ci', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/users.json`, + body: { + user: { + email: 'example@example.com', + password: 'securePassword123', + password_digest: 'hashedPassword', + admin: false + } + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/post-users.test.ts b/.brightsec/tests/post-users.test.ts new file mode 100644 index 0000000..f61822a --- /dev/null +++ b/.brightsec/tests/post-users.test.ts @@ -0,0 +1,48 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('POST /users', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'bopla', 'xss', 'sqli', 'email_injection'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:chore/ci', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.POST, + url: `${baseUrl}/users`, + body: { + user: { + email: 'example@example.com', + password: 'password123', + password_digest: '$2a$12$KIXQ1Yf2oJ2c8', + admin: false + } + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/put-posts-1.test.ts b/.brightsec/tests/put-posts-1.test.ts new file mode 100644 index 0000000..9429c40 --- /dev/null +++ b/.brightsec/tests/put-posts-1.test.ts @@ -0,0 +1,45 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('PUT /posts/1', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['csrf', 'sqli', 'bopla', 'xss'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:chore/ci', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.PUT, + url: `${baseUrl}/posts/1`, + body: { + title: 'Updated Post Title', + content: 'Updated content of the post.', + public: true + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/put-users-123-json.test.ts b/.brightsec/tests/put-users-123-json.test.ts new file mode 100644 index 0000000..b171b59 --- /dev/null +++ b/.brightsec/tests/put-users-123-json.test.ts @@ -0,0 +1,48 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('PUT /users/123.json', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'csrf', 'sqli', 'xss'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:chore/ci', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.PUT, + url: `${baseUrl}/users/123.json`, + body: { + user: { + email: 'example@example.com', + password: 'securepassword', + password_digest: '$2a$12$KIXQ1Y1rZ1u1', + admin: false + } + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file diff --git a/.brightsec/tests/put-users-123.test.ts b/.brightsec/tests/put-users-123.test.ts new file mode 100644 index 0000000..2b087b9 --- /dev/null +++ b/.brightsec/tests/put-users-123.test.ts @@ -0,0 +1,46 @@ +import { test, before, after } from 'node:test'; +import { SecRunner } from '@sectester/runner'; +import { AttackParamLocation, HttpMethod } from '@sectester/scan'; + +const timeout = 40 * 60 * 1000; +const baseUrl = process.env.BRIGHT_TARGET_URL!; + +let runner!: SecRunner; + +before(async () => { + runner = new SecRunner({ + hostname: process.env.BRIGHT_HOSTNAME!, + projectId: process.env.BRIGHT_PROJECT_ID! + }); + + await runner.init(); +}); + +after(() => runner.clear()); + +test('PUT /users/123', { signal: AbortSignal.timeout(timeout) }, async () => { + await runner + .createScan({ + tests: ['bopla', 'csrf', 'sqli', 'xss', 'id_enumeration'], + attackParamLocations: [AttackParamLocation.BODY], + starMetadata: { + code_source: 'NeuraLegion/ruby-example-app:chore/ci', + databases: ['PostgreSQL'], + user_roles: [] + }, + poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined + }) + .setFailFast(false) + .timeout(timeout) + .run({ + method: HttpMethod.PUT, + url: `${baseUrl}/users/123`, + body: { + email: 'user@example.com', + password: 'securepassword', + password_digest: '$2a$12$examplehash', + admin: false + }, + headers: { 'Content-Type': 'application/json' } + }); +}); \ No newline at end of file From bc27d6283bb25eccdd50062c793e600df46c08c5 Mon Sep 17 00:00:00 2001 From: Viachaslau Date: Tue, 17 Feb 2026 22:21:10 +0400 Subject: [PATCH 12/18] ci: add CI workflow to run e2e security tests --- .github/workflows/bright.yml | 131 ++++++++++++++++++ .../configure-bright-credentials/action.yaml | 53 +++++++ 2 files changed, 184 insertions(+) create mode 100644 .github/workflows/bright.yml create mode 100644 .github/workflows/composite/configure-bright-credentials/action.yaml diff --git a/.github/workflows/bright.yml b/.github/workflows/bright.yml new file mode 100644 index 0000000..3667827 --- /dev/null +++ b/.github/workflows/bright.yml @@ -0,0 +1,131 @@ +name: Bright + +on: + pull_request: + branches: + - '**' + +permissions: + checks: write + contents: read + id-token: write + +jobs: + test: + runs-on: ubuntu-latest + container: + image: buildpack-deps:buster + defaults: + run: + shell: bash + services: + postgres: + image: postgres:9.6 + env: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: blog_development + ports: + - 5432:5432 + options: >- + --name postgres + --health-cmd "pg_isready -U postgres" + --health-interval 5s + --health-timeout 5s + --health-retries 10 + env: + PGHOST: postgres + PGPORT: 5432 + PGUSER: postgres + PGPASSWORD: postgres + PGDATABASE: blog_development + DATABASE_URL: postgres://postgres:postgres@postgres:5432/blog_development + steps: + - uses: actions/checkout@v4 + + - name: Point apt to Debian archive + run: | + sed -i 's|deb.debian.org/debian|archive.debian.org/debian|g' /etc/apt/sources.list + sed -i 's|security.debian.org/debian-security|archive.debian.org/debian-security|g' /etc/apt/sources.list + sed -i '/buster-updates/d' /etc/apt/sources.list + + - name: Install system deps + run: | + apt-get -o Acquire::Check-Valid-Until=false -o Acquire::AllowInsecureRepositories=true update + apt-get -o Acquire::Check-Valid-Until=false -o Acquire::AllowInsecureRepositories=true install -y --no-install-recommends \ + build-essential \ + libffi-dev \ + libgdbm-dev \ + libpq-dev \ + libreadline-dev \ + libssl-dev \ + libxml2-dev \ + libxslt1-dev \ + postgresql-client \ + nodejs \ + libyaml-dev \ + zlib1g-dev + + - name: Install Ruby 2.3.3 + env: + RUBY_PREFIX: /opt/ruby-2.3.3 + run: | + git clone --depth=1 https://github.com/rbenv/ruby-build.git /tmp/ruby-build + /tmp/ruby-build/install.sh + ruby-build 2.3.3 "$RUBY_PREFIX" + echo "$RUBY_PREFIX/bin" >> "$GITHUB_PATH" + + - name: Install bundler + run: gem install bundler -v 1.10.6 + + - name: Configure bundler for nokogiri + run: bundle config build.nokogiri --use-system-libraries + + - name: Install gems + run: bundle install + + - name: Setup database + run: bundle exec rake db:create db:migrate db:seed + + - name: Start server + env: + DATABASE_URL: postgres://postgres:postgres@postgres:5432/blog_development + PGDATABASE: blog_development + PGHOST: postgres + PGPASSWORD: postgres + PGPORT: 5432 + PGUSER: postgres + run: | + bundle exec rails server -b 0.0.0.0 -p 3000 >rails.log 2>&1 & + + - name: Wait for server readiness + run: | + for i in {1..30}; do curl -sS -o /dev/null http://127.0.0.1:3000 && exit 0 || sleep 5; done; exit 1 + + - name: Setup Node.js + uses: actions/setup-node@v4 + with: + node-version: 22.x + + - name: Install SecTesterJS dependencies + run: | + npm i --save=false --prefix .brightsec @sectester/core@0.49.0 @sectester/repeater@0.49.0 @sectester/scan@0.49.0 @sectester/runner@0.49.0 @sectester/reporter@0.49.0 + + - name: Authenticate with Bright + uses: ./.github/workflows/composite/configure-bright-credentials + with: + BRIGHT_HOSTNAME: development.playground.brightsec.com + BRIGHT_PROJECT_ID: dhSq9jPULmyZnndTYVtd6o + BRIGHT_TOKEN: ${{ secrets.BRIGHT_TOKEN }} + + - name: Run security tests + env: + BRIGHT_HOSTNAME: development.playground.brightsec.com + BRIGHT_PROJECT_ID: dhSq9jPULmyZnndTYVtd6o + BRIGHT_AUTH_ID: ${{ vars.BRIGHT_AUTH_ID }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + BRIGHT_TOKEN: ${{ env.BRIGHT_TOKEN }} + BRIGHT_TARGET_URL: http://127.0.0.1:3000 + SECTESTER_SCAN_POOL_SIZE: ${{ vars.SECTESTER_SCAN_POOL_SIZE }} + run: | + node --experimental-transform-types --experimental-strip-types --experimental-detect-module --disable-warning=MODULE_TYPELESS_PACKAGE_JSON --disable-warning=ExperimentalWarning --test-force-exit --test-concurrency=4 --test .brightsec/tests/*.test.ts \ No newline at end of file diff --git a/.github/workflows/composite/configure-bright-credentials/action.yaml b/.github/workflows/composite/configure-bright-credentials/action.yaml new file mode 100644 index 0000000..8498384 --- /dev/null +++ b/.github/workflows/composite/configure-bright-credentials/action.yaml @@ -0,0 +1,53 @@ +name: 'Configure BrightSec credentials' + +inputs: + BRIGHT_HOSTNAME: + description: 'Hostname for the BrightSec environment' + required: true + BRIGHT_PROJECT_ID: + description: 'Project ID for BrightSec' + required: true + BRIGHT_TOKEN: + description: 'Pre-configured token' + required: false + +runs: + using: 'composite' + steps: + - id: configure_env_from_input + name: 'Set existing token in env' + shell: bash + if: ${{ inputs.BRIGHT_TOKEN != '' }} + env: + BRIGHT_TOKEN: ${{ inputs.BRIGHT_TOKEN }} + run: | + echo "BRIGHT_TOKEN=${BRIGHT_TOKEN}" >> $GITHUB_ENV + + - id: configure_bright_credentials_through_oidc + name: 'Exchange OIDC credentials for Bright token' + shell: bash + if: ${{ inputs.BRIGHT_TOKEN == '' }} + env: + BRIGHT_HOSTNAME: ${{ inputs.BRIGHT_HOSTNAME }} + BRIGHT_PROJECT_ID: ${{ inputs.BRIGHT_PROJECT_ID }} + run: | + # Retrieve OIDC token from GitHub + OIDC_TOKEN=$(curl -sS -H "Authorization: Bearer $ACTIONS_ID_TOKEN_REQUEST_TOKEN" \ + "${ACTIONS_ID_TOKEN_REQUEST_URL}" | jq -r '.value') + + # Post the token to BrightSec + RESPONSE=$(curl -s -X POST "https://${BRIGHT_HOSTNAME}/api/v1/projects/${BRIGHT_PROJECT_ID}/api-keys/oidc" \ + -H "Content-Type: application/json" \ + -d "{\"token\": \"${OIDC_TOKEN}\"}") + + if ! echo "$RESPONSE" | jq -e . > /dev/null 2>&1; then + echo "Error: $RESPONSE" 1>&2 + exit 1 + fi + + # Extract the pureKey + PURE_KEY=$(echo "$RESPONSE" | jq -r '.pureKey') + + # Mask and store in environment + echo "::add-mask::$PURE_KEY" + echo "BRIGHT_TOKEN=$PURE_KEY" >> $GITHUB_ENV From 29bc1d8a857da03daffc8c51c8fde498a93ea5ed Mon Sep 17 00:00:00 2001 From: Viachaslau Date: Wed, 18 Feb 2026 00:10:38 +0400 Subject: [PATCH 13/18] test: remove completed test files that are no longer relevant skip-checks:true --- .brightsec/tests/delete-logout.test.ts | 39 --------------- .brightsec/tests/delete-posts-1.test.ts | 40 ---------------- .brightsec/tests/delete-users-1-json.test.ts | 39 --------------- .brightsec/tests/delete-users-1.test.ts | 39 --------------- .brightsec/tests/get-login.test.ts | 39 --------------- .brightsec/tests/get-posts-1-edit.test.ts | 39 --------------- .brightsec/tests/get-posts-1.test.ts | 39 --------------- .brightsec/tests/get-root.test.ts | 39 --------------- .brightsec/tests/get-users-1-edit.test.ts | 39 --------------- .brightsec/tests/get-users-1-json.test.ts | 40 ---------------- .../tests/get-users-1-posts-new.test.ts | 39 --------------- .brightsec/tests/get-users-1-posts.test.ts | 39 --------------- .brightsec/tests/get-users-1.test.ts | 39 --------------- .brightsec/tests/get-users-json.test.ts | 39 --------------- .brightsec/tests/get-users-new.test.ts | 39 --------------- .brightsec/tests/get-users.test.ts | 39 --------------- .brightsec/tests/patch-posts-1.test.ts | 45 ----------------- .brightsec/tests/post-login.test.ts | 44 ----------------- .brightsec/tests/post-users-json.test.ts | 48 ------------------- .brightsec/tests/post-users.test.ts | 48 ------------------- .brightsec/tests/put-posts-1.test.ts | 45 ----------------- .brightsec/tests/put-users-123-json.test.ts | 48 ------------------- .brightsec/tests/put-users-123.test.ts | 46 ------------------ 23 files changed, 950 deletions(-) delete mode 100644 .brightsec/tests/delete-logout.test.ts delete mode 100644 .brightsec/tests/delete-posts-1.test.ts delete mode 100644 .brightsec/tests/delete-users-1-json.test.ts delete mode 100644 .brightsec/tests/delete-users-1.test.ts delete mode 100644 .brightsec/tests/get-login.test.ts delete mode 100644 .brightsec/tests/get-posts-1-edit.test.ts delete mode 100644 .brightsec/tests/get-posts-1.test.ts delete mode 100644 .brightsec/tests/get-root.test.ts delete mode 100644 .brightsec/tests/get-users-1-edit.test.ts delete mode 100644 .brightsec/tests/get-users-1-json.test.ts delete mode 100644 .brightsec/tests/get-users-1-posts-new.test.ts delete mode 100644 .brightsec/tests/get-users-1-posts.test.ts delete mode 100644 .brightsec/tests/get-users-1.test.ts delete mode 100644 .brightsec/tests/get-users-json.test.ts delete mode 100644 .brightsec/tests/get-users-new.test.ts delete mode 100644 .brightsec/tests/get-users.test.ts delete mode 100644 .brightsec/tests/patch-posts-1.test.ts delete mode 100644 .brightsec/tests/post-login.test.ts delete mode 100644 .brightsec/tests/post-users-json.test.ts delete mode 100644 .brightsec/tests/post-users.test.ts delete mode 100644 .brightsec/tests/put-posts-1.test.ts delete mode 100644 .brightsec/tests/put-users-123-json.test.ts delete mode 100644 .brightsec/tests/put-users-123.test.ts diff --git a/.brightsec/tests/delete-logout.test.ts b/.brightsec/tests/delete-logout.test.ts deleted file mode 100644 index 956ee51..0000000 --- a/.brightsec/tests/delete-logout.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { test, before, after } from 'node:test'; -import { SecRunner } from '@sectester/runner'; -import { AttackParamLocation, HttpMethod } from '@sectester/scan'; - -const timeout = 40 * 60 * 1000; -const baseUrl = process.env.BRIGHT_TARGET_URL!; - -let runner!: SecRunner; - -before(async () => { - runner = new SecRunner({ - hostname: process.env.BRIGHT_HOSTNAME!, - projectId: process.env.BRIGHT_PROJECT_ID! - }); - - await runner.init(); -}); - -after(() => runner.clear()); - -test('DELETE /logout', { signal: AbortSignal.timeout(timeout) }, async () => { - await runner - .createScan({ - tests: ['csrf', 'http_method_fuzzing'], - attackParamLocations: [AttackParamLocation.PATH], - starMetadata: { - code_source: 'NeuraLegion/ruby-example-app:chore/ci', - databases: ['PostgreSQL'], - user_roles: [] - }, - poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined - }) - .setFailFast(false) - .timeout(timeout) - .run({ - method: HttpMethod.DELETE, - url: `${baseUrl}/logout` - }); -}); \ No newline at end of file diff --git a/.brightsec/tests/delete-posts-1.test.ts b/.brightsec/tests/delete-posts-1.test.ts deleted file mode 100644 index 82db847..0000000 --- a/.brightsec/tests/delete-posts-1.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { test, before, after } from 'node:test'; -import { SecRunner } from '@sectester/runner'; -import { AttackParamLocation, HttpMethod } from '@sectester/scan'; - -const timeout = 40 * 60 * 1000; -const baseUrl = process.env.BRIGHT_TARGET_URL!; - -let runner!: SecRunner; - -before(async () => { - runner = new SecRunner({ - hostname: process.env.BRIGHT_HOSTNAME!, - projectId: process.env.BRIGHT_PROJECT_ID! - }); - - await runner.init(); -}); - -after(() => runner.clear()); - -test('DELETE /posts/1', { signal: AbortSignal.timeout(timeout) }, async () => { - await runner - .createScan({ - tests: ['csrf', 'bopla', 'id_enumeration'], - attackParamLocations: [AttackParamLocation.PATH], - starMetadata: { - code_source: 'NeuraLegion/ruby-example-app:chore/ci', - databases: ['PostgreSQL'], - user_roles: [] - }, - poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined - }) - .setFailFast(false) - .timeout(timeout) - .run({ - method: HttpMethod.DELETE, - url: `${baseUrl}/posts/1`, - headers: { 'Content-Type': 'application/json' } - }); -}); \ No newline at end of file diff --git a/.brightsec/tests/delete-users-1-json.test.ts b/.brightsec/tests/delete-users-1-json.test.ts deleted file mode 100644 index 92559f5..0000000 --- a/.brightsec/tests/delete-users-1-json.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { test, before, after } from 'node:test'; -import { SecRunner } from '@sectester/runner'; -import { AttackParamLocation, HttpMethod } from '@sectester/scan'; - -const timeout = 40 * 60 * 1000; -const baseUrl = process.env.BRIGHT_TARGET_URL!; - -let runner!: SecRunner; - -before(async () => { - runner = new SecRunner({ - hostname: process.env.BRIGHT_HOSTNAME!, - projectId: process.env.BRIGHT_PROJECT_ID! - }); - - await runner.init(); -}); - -after(() => runner.clear()); - -test('DELETE /users/1.json', { signal: AbortSignal.timeout(timeout) }, async () => { - await runner - .createScan({ - tests: ['csrf', 'bopla', 'id_enumeration', 'sqli'], - attackParamLocations: [AttackParamLocation.PATH], - starMetadata: { - code_source: 'NeuraLegion/ruby-example-app:chore/ci', - databases: ['PostgreSQL'], - user_roles: [] - }, - poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined - }) - .setFailFast(false) - .timeout(timeout) - .run({ - method: HttpMethod.DELETE, - url: `${baseUrl}/users/1.json` - }); -}); \ No newline at end of file diff --git a/.brightsec/tests/delete-users-1.test.ts b/.brightsec/tests/delete-users-1.test.ts deleted file mode 100644 index 7943ee0..0000000 --- a/.brightsec/tests/delete-users-1.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { test, before, after } from 'node:test'; -import { SecRunner } from '@sectester/runner'; -import { AttackParamLocation, HttpMethod } from '@sectester/scan'; - -const timeout = 40 * 60 * 1000; -const baseUrl = process.env.BRIGHT_TARGET_URL!; - -let runner!: SecRunner; - -before(async () => { - runner = new SecRunner({ - hostname: process.env.BRIGHT_HOSTNAME!, - projectId: process.env.BRIGHT_PROJECT_ID! - }); - - await runner.init(); -}); - -after(() => runner.clear()); - -test('DELETE /users/1', { signal: AbortSignal.timeout(timeout) }, async () => { - await runner - .createScan({ - tests: ['csrf', 'bopla', 'id_enumeration', 'sqli'], - attackParamLocations: [AttackParamLocation.PATH], - starMetadata: { - code_source: 'NeuraLegion/ruby-example-app:chore/ci', - databases: ['PostgreSQL'], - user_roles: [] - }, - poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined - }) - .setFailFast(false) - .timeout(timeout) - .run({ - method: HttpMethod.DELETE, - url: `${baseUrl}/users/1` - }); -}); \ No newline at end of file diff --git a/.brightsec/tests/get-login.test.ts b/.brightsec/tests/get-login.test.ts deleted file mode 100644 index d329249..0000000 --- a/.brightsec/tests/get-login.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { test, before, after } from 'node:test'; -import { SecRunner } from '@sectester/runner'; -import { AttackParamLocation, HttpMethod } from '@sectester/scan'; - -const timeout = 40 * 60 * 1000; -const baseUrl = process.env.BRIGHT_TARGET_URL!; - -let runner!: SecRunner; - -before(async () => { - runner = new SecRunner({ - hostname: process.env.BRIGHT_HOSTNAME!, - projectId: process.env.BRIGHT_PROJECT_ID! - }); - - await runner.init(); -}); - -after(() => runner.clear()); - -test('GET /login', { signal: AbortSignal.timeout(timeout) }, async () => { - await runner - .createScan({ - tests: ['csrf', 'sqli', 'xss', 'unvalidated_redirect', 'secret_tokens'], - attackParamLocations: [AttackParamLocation.QUERY, AttackParamLocation.HEADER], - starMetadata: { - code_source: 'NeuraLegion/ruby-example-app:chore/ci', - databases: ['PostgreSQL'], - user_roles: [] - }, - poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined - }) - .setFailFast(false) - .timeout(timeout) - .run({ - method: HttpMethod.GET, - url: `${baseUrl}/login` - }); -}); \ No newline at end of file diff --git a/.brightsec/tests/get-posts-1-edit.test.ts b/.brightsec/tests/get-posts-1-edit.test.ts deleted file mode 100644 index 7c08ba1..0000000 --- a/.brightsec/tests/get-posts-1-edit.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { test, before, after } from 'node:test'; -import { SecRunner } from '@sectester/runner'; -import { AttackParamLocation, HttpMethod } from '@sectester/scan'; - -const timeout = 40 * 60 * 1000; -const baseUrl = process.env.BRIGHT_TARGET_URL!; - -let runner!: SecRunner; - -before(async () => { - runner = new SecRunner({ - hostname: process.env.BRIGHT_HOSTNAME!, - projectId: process.env.BRIGHT_PROJECT_ID! - }); - - await runner.init(); -}); - -after(() => runner.clear()); - -test('GET /posts/1/edit', { signal: AbortSignal.timeout(timeout) }, async () => { - await runner - .createScan({ - tests: ['csrf', 'bopla', 'xss', 'id_enumeration', 'sqli'], - attackParamLocations: [AttackParamLocation.PATH], - starMetadata: { - code_source: 'NeuraLegion/ruby-example-app:chore/ci', - databases: ['PostgreSQL'], - user_roles: [] - }, - poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined - }) - .setFailFast(false) - .timeout(timeout) - .run({ - method: HttpMethod.GET, - url: `${baseUrl}/posts/1/edit` - }); -}); \ No newline at end of file diff --git a/.brightsec/tests/get-posts-1.test.ts b/.brightsec/tests/get-posts-1.test.ts deleted file mode 100644 index d2622dc..0000000 --- a/.brightsec/tests/get-posts-1.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { test, before, after } from 'node:test'; -import { SecRunner } from '@sectester/runner'; -import { AttackParamLocation, HttpMethod } from '@sectester/scan'; - -const timeout = 40 * 60 * 1000; -const baseUrl = process.env.BRIGHT_TARGET_URL!; - -let runner!: SecRunner; - -before(async () => { - runner = new SecRunner({ - hostname: process.env.BRIGHT_HOSTNAME!, - projectId: process.env.BRIGHT_PROJECT_ID! - }); - - await runner.init(); -}); - -after(() => runner.clear()); - -test('GET /posts/1', { signal: AbortSignal.timeout(timeout) }, async () => { - await runner - .createScan({ - tests: ['csrf', 'id_enumeration', 'sqli', 'xss', 'bopla'], - attackParamLocations: [AttackParamLocation.PATH], - starMetadata: { - code_source: 'NeuraLegion/ruby-example-app:chore/ci', - databases: ['PostgreSQL'], - user_roles: [] - }, - poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined - }) - .setFailFast(false) - .timeout(timeout) - .run({ - method: HttpMethod.GET, - url: `${baseUrl}/posts/1` - }); -}); \ No newline at end of file diff --git a/.brightsec/tests/get-root.test.ts b/.brightsec/tests/get-root.test.ts deleted file mode 100644 index d6b0e6c..0000000 --- a/.brightsec/tests/get-root.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { test, before, after } from 'node:test'; -import { SecRunner } from '@sectester/runner'; -import { AttackParamLocation, HttpMethod } from '@sectester/scan'; - -const timeout = 40 * 60 * 1000; -const baseUrl = process.env.BRIGHT_TARGET_URL!; - -let runner!: SecRunner; - -before(async () => { - runner = new SecRunner({ - hostname: process.env.BRIGHT_HOSTNAME!, - projectId: process.env.BRIGHT_PROJECT_ID! - }); - - await runner.init(); -}); - -after(() => runner.clear()); - -test('GET /', { signal: AbortSignal.timeout(timeout) }, async () => { - await runner - .createScan({ - tests: ['sqli', 'csrf', 'xss', 'bopla'], - attackParamLocations: [AttackParamLocation.PATH, AttackParamLocation.QUERY], - starMetadata: { - code_source: 'NeuraLegion/ruby-example-app:chore/ci', - databases: ['PostgreSQL'], - user_roles: [] - }, - poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined - }) - .setFailFast(false) - .timeout(timeout) - .run({ - method: HttpMethod.GET, - url: `${baseUrl}/` - }); -}); \ No newline at end of file diff --git a/.brightsec/tests/get-users-1-edit.test.ts b/.brightsec/tests/get-users-1-edit.test.ts deleted file mode 100644 index 002e4ba..0000000 --- a/.brightsec/tests/get-users-1-edit.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { test, before, after } from 'node:test'; -import { SecRunner } from '@sectester/runner'; -import { AttackParamLocation, HttpMethod } from '@sectester/scan'; - -const timeout = 40 * 60 * 1000; -const baseUrl = process.env.BRIGHT_TARGET_URL!; - -let runner!: SecRunner; - -before(async () => { - runner = new SecRunner({ - hostname: process.env.BRIGHT_HOSTNAME!, - projectId: process.env.BRIGHT_PROJECT_ID! - }); - - await runner.init(); -}); - -after(() => runner.clear()); - -test('GET /users/1/edit', { signal: AbortSignal.timeout(timeout) }, async () => { - await runner - .createScan({ - tests: ['csrf', 'bopla', 'id_enumeration', 'xss'], - attackParamLocations: [AttackParamLocation.PATH], - starMetadata: { - code_source: 'NeuraLegion/ruby-example-app:chore/ci', - databases: ['PostgreSQL'], - user_roles: [] - }, - poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined - }) - .setFailFast(false) - .timeout(timeout) - .run({ - method: HttpMethod.GET, - url: `${baseUrl}/users/1/edit` - }); -}); \ No newline at end of file diff --git a/.brightsec/tests/get-users-1-json.test.ts b/.brightsec/tests/get-users-1-json.test.ts deleted file mode 100644 index 5b41b23..0000000 --- a/.brightsec/tests/get-users-1-json.test.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { test, before, after } from 'node:test'; -import { SecRunner } from '@sectester/runner'; -import { AttackParamLocation, HttpMethod } from '@sectester/scan'; - -const timeout = 40 * 60 * 1000; -const baseUrl = process.env.BRIGHT_TARGET_URL!; - -let runner!: SecRunner; - -before(async () => { - runner = new SecRunner({ - hostname: process.env.BRIGHT_HOSTNAME!, - projectId: process.env.BRIGHT_PROJECT_ID! - }); - - await runner.init(); -}); - -after(() => runner.clear()); - -test('GET /users/1.json', { signal: AbortSignal.timeout(timeout) }, async () => { - await runner - .createScan({ - tests: ['id_enumeration', 'bopla', 'sqli', 'xss'], - attackParamLocations: [AttackParamLocation.PATH], - starMetadata: { - code_source: 'NeuraLegion/ruby-example-app:chore/ci', - databases: ['PostgreSQL'], - user_roles: [] - }, - poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined - }) - .setFailFast(false) - .timeout(timeout) - .run({ - method: HttpMethod.GET, - url: `${baseUrl}/users/1.json`, - headers: { 'Accept': 'application/json' } - }); -}); \ No newline at end of file diff --git a/.brightsec/tests/get-users-1-posts-new.test.ts b/.brightsec/tests/get-users-1-posts-new.test.ts deleted file mode 100644 index 45db074..0000000 --- a/.brightsec/tests/get-users-1-posts-new.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { test, before, after } from 'node:test'; -import { SecRunner } from '@sectester/runner'; -import { AttackParamLocation, HttpMethod } from '@sectester/scan'; - -const timeout = 40 * 60 * 1000; -const baseUrl = process.env.BRIGHT_TARGET_URL!; - -let runner!: SecRunner; - -before(async () => { - runner = new SecRunner({ - hostname: process.env.BRIGHT_HOSTNAME!, - projectId: process.env.BRIGHT_PROJECT_ID! - }); - - await runner.init(); -}); - -after(() => runner.clear()); - -test('GET /users/1/posts/new', { signal: AbortSignal.timeout(timeout) }, async () => { - await runner - .createScan({ - tests: ['csrf', 'xss', 'bopla'], - attackParamLocations: [AttackParamLocation.PATH], - starMetadata: { - code_source: 'NeuraLegion/ruby-example-app:chore/ci', - databases: ['PostgreSQL'], - user_roles: [] - }, - poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined - }) - .setFailFast(false) - .timeout(timeout) - .run({ - method: HttpMethod.GET, - url: `${baseUrl}/users/1/posts/new` - }); -}); \ No newline at end of file diff --git a/.brightsec/tests/get-users-1-posts.test.ts b/.brightsec/tests/get-users-1-posts.test.ts deleted file mode 100644 index 930c8ea..0000000 --- a/.brightsec/tests/get-users-1-posts.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { test, before, after } from 'node:test'; -import { SecRunner } from '@sectester/runner'; -import { AttackParamLocation, HttpMethod } from '@sectester/scan'; - -const timeout = 40 * 60 * 1000; -const baseUrl = process.env.BRIGHT_TARGET_URL!; - -let runner!: SecRunner; - -before(async () => { - runner = new SecRunner({ - hostname: process.env.BRIGHT_HOSTNAME!, - projectId: process.env.BRIGHT_PROJECT_ID! - }); - - await runner.init(); -}); - -after(() => runner.clear()); - -test('GET /users/1/posts', { signal: AbortSignal.timeout(timeout) }, async () => { - await runner - .createScan({ - tests: ['csrf', 'sqli', 'id_enumeration', 'xss', 'bopla'], - attackParamLocations: [AttackParamLocation.PATH], - starMetadata: { - code_source: 'NeuraLegion/ruby-example-app:chore/ci', - databases: ['PostgreSQL'], - user_roles: [] - }, - poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined - }) - .setFailFast(false) - .timeout(timeout) - .run({ - method: HttpMethod.GET, - url: `${baseUrl}/users/1/posts` - }); -}); \ No newline at end of file diff --git a/.brightsec/tests/get-users-1.test.ts b/.brightsec/tests/get-users-1.test.ts deleted file mode 100644 index 98be69f..0000000 --- a/.brightsec/tests/get-users-1.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { test, before, after } from 'node:test'; -import { SecRunner } from '@sectester/runner'; -import { AttackParamLocation, HttpMethod } from '@sectester/scan'; - -const timeout = 40 * 60 * 1000; -const baseUrl = process.env.BRIGHT_TARGET_URL!; - -let runner!: SecRunner; - -before(async () => { - runner = new SecRunner({ - hostname: process.env.BRIGHT_HOSTNAME!, - projectId: process.env.BRIGHT_PROJECT_ID! - }); - - await runner.init(); -}); - -after(() => runner.clear()); - -test('GET /users/1', { signal: AbortSignal.timeout(timeout) }, async () => { - await runner - .createScan({ - tests: ['id_enumeration', 'bopla', 'sqli', 'xss', 'csrf'], - attackParamLocations: [AttackParamLocation.PATH], - starMetadata: { - code_source: "NeuraLegion/ruby-example-app:chore/ci", - databases: ["PostgreSQL"], - user_roles: [] - }, - poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined - }) - .setFailFast(false) - .timeout(timeout) - .run({ - method: HttpMethod.GET, - url: `${baseUrl}/users/1` - }); -}); \ No newline at end of file diff --git a/.brightsec/tests/get-users-json.test.ts b/.brightsec/tests/get-users-json.test.ts deleted file mode 100644 index 4dca5fd..0000000 --- a/.brightsec/tests/get-users-json.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { test, before, after } from 'node:test'; -import { SecRunner } from '@sectester/runner'; -import { AttackParamLocation, HttpMethod } from '@sectester/scan'; - -const timeout = 40 * 60 * 1000; -const baseUrl = process.env.BRIGHT_TARGET_URL!; - -let runner!: SecRunner; - -before(async () => { - runner = new SecRunner({ - hostname: process.env.BRIGHT_HOSTNAME!, - projectId: process.env.BRIGHT_PROJECT_ID! - }); - - await runner.init(); -}); - -after(() => runner.clear()); - -test('GET /users.json', { signal: AbortSignal.timeout(timeout) }, async () => { - await runner - .createScan({ - tests: ['bopla', 'id_enumeration', 'improper_asset_management', 'xss'], - attackParamLocations: [AttackParamLocation.PATH], - starMetadata: { - code_source: 'NeuraLegion/ruby-example-app:chore/ci', - databases: ['PostgreSQL'], - user_roles: [] - }, - poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined - }) - .setFailFast(false) - .timeout(timeout) - .run({ - method: HttpMethod.GET, - url: `${baseUrl}/users.json` - }); -}); \ No newline at end of file diff --git a/.brightsec/tests/get-users-new.test.ts b/.brightsec/tests/get-users-new.test.ts deleted file mode 100644 index b39a3f8..0000000 --- a/.brightsec/tests/get-users-new.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { test, before, after } from 'node:test'; -import { SecRunner } from '@sectester/runner'; -import { AttackParamLocation, HttpMethod } from '@sectester/scan'; - -const timeout = 40 * 60 * 1000; -const baseUrl = process.env.BRIGHT_TARGET_URL!; - -let runner!: SecRunner; - -before(async () => { - runner = new SecRunner({ - hostname: process.env.BRIGHT_HOSTNAME!, - projectId: process.env.BRIGHT_PROJECT_ID! - }); - - await runner.init(); -}); - -after(() => runner.clear()); - -test('GET /users/new', { signal: AbortSignal.timeout(timeout) }, async () => { - await runner - .createScan({ - tests: ['csrf', 'xss', 'html_injection', 'bopla'], - attackParamLocations: [AttackParamLocation.PATH], - starMetadata: { - code_source: 'NeuraLegion/ruby-example-app:chore/ci', - databases: ['PostgreSQL'], - user_roles: [] - }, - poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined - }) - .setFailFast(false) - .timeout(timeout) - .run({ - method: HttpMethod.GET, - url: `${baseUrl}/users/new` - }); -}); \ No newline at end of file diff --git a/.brightsec/tests/get-users.test.ts b/.brightsec/tests/get-users.test.ts deleted file mode 100644 index 10ab3bc..0000000 --- a/.brightsec/tests/get-users.test.ts +++ /dev/null @@ -1,39 +0,0 @@ -import { test, before, after } from 'node:test'; -import { SecRunner } from '@sectester/runner'; -import { AttackParamLocation, HttpMethod } from '@sectester/scan'; - -const timeout = 40 * 60 * 1000; -const baseUrl = process.env.BRIGHT_TARGET_URL!; - -let runner!: SecRunner; - -before(async () => { - runner = new SecRunner({ - hostname: process.env.BRIGHT_HOSTNAME!, - projectId: process.env.BRIGHT_PROJECT_ID! - }); - - await runner.init(); -}); - -after(() => runner.clear()); - -test('GET /users', { signal: AbortSignal.timeout(timeout) }, async () => { - await runner - .createScan({ - tests: ['bopla', 'id_enumeration', 'improper_asset_management', 'sqli', 'xss'], - attackParamLocations: [AttackParamLocation.QUERY], - starMetadata: { - code_source: 'NeuraLegion/ruby-example-app:chore/ci', - databases: ['PostgreSQL'], - user_roles: [] - }, - poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined - }) - .setFailFast(false) - .timeout(timeout) - .run({ - method: HttpMethod.GET, - url: `${baseUrl}/users` - }); -}); \ No newline at end of file diff --git a/.brightsec/tests/patch-posts-1.test.ts b/.brightsec/tests/patch-posts-1.test.ts deleted file mode 100644 index 7d7b139..0000000 --- a/.brightsec/tests/patch-posts-1.test.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { test, before, after } from 'node:test'; -import { SecRunner } from '@sectester/runner'; -import { AttackParamLocation, HttpMethod } from '@sectester/scan'; - -const timeout = 40 * 60 * 1000; -const baseUrl = process.env.BRIGHT_TARGET_URL!; - -let runner!: SecRunner; - -before(async () => { - runner = new SecRunner({ - hostname: process.env.BRIGHT_HOSTNAME!, - projectId: process.env.BRIGHT_PROJECT_ID! - }); - - await runner.init(); -}); - -after(() => runner.clear()); - -test('PATCH /posts/1', { signal: AbortSignal.timeout(timeout) }, async () => { - await runner - .createScan({ - tests: ['csrf', 'bopla', 'sqli', 'xss', 'id_enumeration'], - attackParamLocations: [AttackParamLocation.BODY], - starMetadata: { - code_source: 'NeuraLegion/ruby-example-app:chore/ci', - databases: ['PostgreSQL'], - user_roles: [] - }, - poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined - }) - .setFailFast(false) - .timeout(timeout) - .run({ - method: HttpMethod.PATCH, - url: `${baseUrl}/posts/1`, - body: { - title: 'Updated Title', - content: 'Updated content of the post.', - public: true - }, - headers: { 'Content-Type': 'application/json' } - }); -}); \ No newline at end of file diff --git a/.brightsec/tests/post-login.test.ts b/.brightsec/tests/post-login.test.ts deleted file mode 100644 index bca2404..0000000 --- a/.brightsec/tests/post-login.test.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { test, before, after } from 'node:test'; -import { SecRunner } from '@sectester/runner'; -import { AttackParamLocation, HttpMethod } from '@sectester/scan'; - -const timeout = 40 * 60 * 1000; -const baseUrl = process.env.BRIGHT_TARGET_URL!; - -let runner!: SecRunner; - -before(async () => { - runner = new SecRunner({ - hostname: process.env.BRIGHT_HOSTNAME!, - projectId: process.env.BRIGHT_PROJECT_ID! - }); - - await runner.init(); -}); - -after(() => runner.clear()); - -test('POST /login', { signal: AbortSignal.timeout(timeout) }, async () => { - await runner - .createScan({ - tests: ['csrf', 'sqli', 'xss', 'unvalidated_redirect', 'secret_tokens'], - attackParamLocations: [AttackParamLocation.BODY], - starMetadata: { - code_source: 'NeuraLegion/ruby-example-app:chore/ci', - databases: ['PostgreSQL'], - user_roles: [] - }, - poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined - }) - .setFailFast(false) - .timeout(timeout) - .run({ - method: HttpMethod.POST, - url: `${baseUrl}/login`, - body: { - email: 'user@example.com', - password: 'securepassword' - }, - headers: { 'Content-Type': 'application/x-www-form-urlencoded' } - }); -}); \ No newline at end of file diff --git a/.brightsec/tests/post-users-json.test.ts b/.brightsec/tests/post-users-json.test.ts deleted file mode 100644 index 68151ea..0000000 --- a/.brightsec/tests/post-users-json.test.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { test, before, after } from 'node:test'; -import { SecRunner } from '@sectester/runner'; -import { AttackParamLocation, HttpMethod } from '@sectester/scan'; - -const timeout = 40 * 60 * 1000; -const baseUrl = process.env.BRIGHT_TARGET_URL!; - -let runner!: SecRunner; - -before(async () => { - runner = new SecRunner({ - hostname: process.env.BRIGHT_HOSTNAME!, - projectId: process.env.BRIGHT_PROJECT_ID! - }); - - await runner.init(); -}); - -after(() => runner.clear()); - -test('POST /users.json', { signal: AbortSignal.timeout(timeout) }, async () => { - await runner - .createScan({ - tests: ['csrf', 'bopla', 'sqli', 'xss', 'secret_tokens'], - attackParamLocations: [AttackParamLocation.BODY], - starMetadata: { - code_source: 'NeuraLegion/ruby-example-app:chore/ci', - databases: ['PostgreSQL'], - user_roles: [] - }, - poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined - }) - .setFailFast(false) - .timeout(timeout) - .run({ - method: HttpMethod.POST, - url: `${baseUrl}/users.json`, - body: { - user: { - email: 'example@example.com', - password: 'securePassword123', - password_digest: 'hashedPassword', - admin: false - } - }, - headers: { 'Content-Type': 'application/json' } - }); -}); \ No newline at end of file diff --git a/.brightsec/tests/post-users.test.ts b/.brightsec/tests/post-users.test.ts deleted file mode 100644 index f61822a..0000000 --- a/.brightsec/tests/post-users.test.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { test, before, after } from 'node:test'; -import { SecRunner } from '@sectester/runner'; -import { AttackParamLocation, HttpMethod } from '@sectester/scan'; - -const timeout = 40 * 60 * 1000; -const baseUrl = process.env.BRIGHT_TARGET_URL!; - -let runner!: SecRunner; - -before(async () => { - runner = new SecRunner({ - hostname: process.env.BRIGHT_HOSTNAME!, - projectId: process.env.BRIGHT_PROJECT_ID! - }); - - await runner.init(); -}); - -after(() => runner.clear()); - -test('POST /users', { signal: AbortSignal.timeout(timeout) }, async () => { - await runner - .createScan({ - tests: ['csrf', 'bopla', 'xss', 'sqli', 'email_injection'], - attackParamLocations: [AttackParamLocation.BODY], - starMetadata: { - code_source: 'NeuraLegion/ruby-example-app:chore/ci', - databases: ['PostgreSQL'], - user_roles: [] - }, - poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined - }) - .setFailFast(false) - .timeout(timeout) - .run({ - method: HttpMethod.POST, - url: `${baseUrl}/users`, - body: { - user: { - email: 'example@example.com', - password: 'password123', - password_digest: '$2a$12$KIXQ1Yf2oJ2c8', - admin: false - } - }, - headers: { 'Content-Type': 'application/json' } - }); -}); \ No newline at end of file diff --git a/.brightsec/tests/put-posts-1.test.ts b/.brightsec/tests/put-posts-1.test.ts deleted file mode 100644 index 9429c40..0000000 --- a/.brightsec/tests/put-posts-1.test.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { test, before, after } from 'node:test'; -import { SecRunner } from '@sectester/runner'; -import { AttackParamLocation, HttpMethod } from '@sectester/scan'; - -const timeout = 40 * 60 * 1000; -const baseUrl = process.env.BRIGHT_TARGET_URL!; - -let runner!: SecRunner; - -before(async () => { - runner = new SecRunner({ - hostname: process.env.BRIGHT_HOSTNAME!, - projectId: process.env.BRIGHT_PROJECT_ID! - }); - - await runner.init(); -}); - -after(() => runner.clear()); - -test('PUT /posts/1', { signal: AbortSignal.timeout(timeout) }, async () => { - await runner - .createScan({ - tests: ['csrf', 'sqli', 'bopla', 'xss'], - attackParamLocations: [AttackParamLocation.BODY], - starMetadata: { - code_source: 'NeuraLegion/ruby-example-app:chore/ci', - databases: ['PostgreSQL'], - user_roles: [] - }, - poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined - }) - .setFailFast(false) - .timeout(timeout) - .run({ - method: HttpMethod.PUT, - url: `${baseUrl}/posts/1`, - body: { - title: 'Updated Post Title', - content: 'Updated content of the post.', - public: true - }, - headers: { 'Content-Type': 'application/json' } - }); -}); \ No newline at end of file diff --git a/.brightsec/tests/put-users-123-json.test.ts b/.brightsec/tests/put-users-123-json.test.ts deleted file mode 100644 index b171b59..0000000 --- a/.brightsec/tests/put-users-123-json.test.ts +++ /dev/null @@ -1,48 +0,0 @@ -import { test, before, after } from 'node:test'; -import { SecRunner } from '@sectester/runner'; -import { AttackParamLocation, HttpMethod } from '@sectester/scan'; - -const timeout = 40 * 60 * 1000; -const baseUrl = process.env.BRIGHT_TARGET_URL!; - -let runner!: SecRunner; - -before(async () => { - runner = new SecRunner({ - hostname: process.env.BRIGHT_HOSTNAME!, - projectId: process.env.BRIGHT_PROJECT_ID! - }); - - await runner.init(); -}); - -after(() => runner.clear()); - -test('PUT /users/123.json', { signal: AbortSignal.timeout(timeout) }, async () => { - await runner - .createScan({ - tests: ['bopla', 'csrf', 'sqli', 'xss'], - attackParamLocations: [AttackParamLocation.BODY], - starMetadata: { - code_source: 'NeuraLegion/ruby-example-app:chore/ci', - databases: ['PostgreSQL'], - user_roles: [] - }, - poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined - }) - .setFailFast(false) - .timeout(timeout) - .run({ - method: HttpMethod.PUT, - url: `${baseUrl}/users/123.json`, - body: { - user: { - email: 'example@example.com', - password: 'securepassword', - password_digest: '$2a$12$KIXQ1Y1rZ1u1', - admin: false - } - }, - headers: { 'Content-Type': 'application/json' } - }); -}); \ No newline at end of file diff --git a/.brightsec/tests/put-users-123.test.ts b/.brightsec/tests/put-users-123.test.ts deleted file mode 100644 index 2b087b9..0000000 --- a/.brightsec/tests/put-users-123.test.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { test, before, after } from 'node:test'; -import { SecRunner } from '@sectester/runner'; -import { AttackParamLocation, HttpMethod } from '@sectester/scan'; - -const timeout = 40 * 60 * 1000; -const baseUrl = process.env.BRIGHT_TARGET_URL!; - -let runner!: SecRunner; - -before(async () => { - runner = new SecRunner({ - hostname: process.env.BRIGHT_HOSTNAME!, - projectId: process.env.BRIGHT_PROJECT_ID! - }); - - await runner.init(); -}); - -after(() => runner.clear()); - -test('PUT /users/123', { signal: AbortSignal.timeout(timeout) }, async () => { - await runner - .createScan({ - tests: ['bopla', 'csrf', 'sqli', 'xss', 'id_enumeration'], - attackParamLocations: [AttackParamLocation.BODY], - starMetadata: { - code_source: 'NeuraLegion/ruby-example-app:chore/ci', - databases: ['PostgreSQL'], - user_roles: [] - }, - poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined - }) - .setFailFast(false) - .timeout(timeout) - .run({ - method: HttpMethod.PUT, - url: `${baseUrl}/users/123`, - body: { - email: 'user@example.com', - password: 'securepassword', - password_digest: '$2a$12$examplehash', - admin: false - }, - headers: { 'Content-Type': 'application/json' } - }); -}); \ No newline at end of file From d850949877e9f8475aef9e335f563504bd9ab95a Mon Sep 17 00:00:00 2001 From: Viachaslau Date: Wed, 18 Feb 2026 00:10:53 +0400 Subject: [PATCH 14/18] test: optimize security tests to focus on specific vulnerabilities skip-checks:true --- .brightsec/tests/get-posts-search.test.ts | 4 ++-- .brightsec/tests/patch-users-123.test.ts | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.brightsec/tests/get-posts-search.test.ts b/.brightsec/tests/get-posts-search.test.ts index 9bc87c4..ca96188 100644 --- a/.brightsec/tests/get-posts-search.test.ts +++ b/.brightsec/tests/get-posts-search.test.ts @@ -21,7 +21,7 @@ after(() => runner.clear()); test('GET /posts/search?search_term=example', { signal: AbortSignal.timeout(timeout) }, async () => { await runner .createScan({ - tests: ['sqli', 'xss', 'csrf', 'business_constraint_bypass'], + tests: ['csrf'], attackParamLocations: [AttackParamLocation.QUERY], starMetadata: { code_source: 'NeuraLegion/ruby-example-app:chore/ci', @@ -36,4 +36,4 @@ test('GET /posts/search?search_term=example', { signal: AbortSignal.timeout(time method: HttpMethod.GET, url: `${baseUrl}/posts/search?search_term=example` }); -}); \ No newline at end of file +}); diff --git a/.brightsec/tests/patch-users-123.test.ts b/.brightsec/tests/patch-users-123.test.ts index d641873..5df80d1 100644 --- a/.brightsec/tests/patch-users-123.test.ts +++ b/.brightsec/tests/patch-users-123.test.ts @@ -21,7 +21,7 @@ after(() => runner.clear()); test('PATCH /users/123', { signal: AbortSignal.timeout(timeout) }, async () => { await runner .createScan({ - tests: ['bopla', 'csrf', 'sqli', 'xss'], + tests: ['sqli'], attackParamLocations: [AttackParamLocation.BODY], starMetadata: { code_source: 'NeuraLegion/ruby-example-app:chore/ci', @@ -43,4 +43,4 @@ test('PATCH /users/123', { signal: AbortSignal.timeout(timeout) }, async () => { }, headers: { 'Content-Type': 'application/json' } }); -}); \ No newline at end of file +}); From 4803cf253124d90e0f5a41eda7fdae555a2c3663 Mon Sep 17 00:00:00 2001 From: Viachaslau Date: Wed, 18 Feb 2026 00:11:39 +0400 Subject: [PATCH 15/18] fix: apply automated fixes for detected vulnerabilities --- app/controllers/posts_controller.rb | 3 ++- app/controllers/users_controller.rb | 4 ++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index 7b16be7..2892213 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -1,6 +1,7 @@ class PostsController < ApplicationController before_action :confirm_logged_in before_action :set_post, only: [:show, :edit, :update, :destroy] + before_action :verify_authenticity_token, only: [:search] # GET /posts # GET /posts.json @@ -99,4 +100,4 @@ def set_post def post_params params.require(:post).permit(:title, :content, :public) end -end +end \ No newline at end of file diff --git a/app/controllers/users_controller.rb b/app/controllers/users_controller.rb index 671381c..4556f48 100644 --- a/app/controllers/users_controller.rb +++ b/app/controllers/users_controller.rb @@ -70,6 +70,6 @@ def set_user # Never trust parameters from the scary internet, only allow the white list through. def user_params - params.require(:user).permit(:email, :password, :password_digest, :admin) + params.require(:user).permit(:email, :password, :admin) end -end +end \ No newline at end of file From 8d5a129d00816492e03b43df8a80b262d3da42cc Mon Sep 17 00:00:00 2001 From: Viachaslau Date: Wed, 18 Feb 2026 00:22:24 +0400 Subject: [PATCH 16/18] test: remove completed test files that are no longer relevant skip-checks:true --- .brightsec/tests/patch-users-123.test.ts | 46 ------------------------ 1 file changed, 46 deletions(-) delete mode 100644 .brightsec/tests/patch-users-123.test.ts diff --git a/.brightsec/tests/patch-users-123.test.ts b/.brightsec/tests/patch-users-123.test.ts deleted file mode 100644 index 5df80d1..0000000 --- a/.brightsec/tests/patch-users-123.test.ts +++ /dev/null @@ -1,46 +0,0 @@ -import { test, before, after } from 'node:test'; -import { SecRunner } from '@sectester/runner'; -import { AttackParamLocation, HttpMethod } from '@sectester/scan'; - -const timeout = 40 * 60 * 1000; -const baseUrl = process.env.BRIGHT_TARGET_URL!; - -let runner!: SecRunner; - -before(async () => { - runner = new SecRunner({ - hostname: process.env.BRIGHT_HOSTNAME!, - projectId: process.env.BRIGHT_PROJECT_ID! - }); - - await runner.init(); -}); - -after(() => runner.clear()); - -test('PATCH /users/123', { signal: AbortSignal.timeout(timeout) }, async () => { - await runner - .createScan({ - tests: ['sqli'], - attackParamLocations: [AttackParamLocation.BODY], - starMetadata: { - code_source: 'NeuraLegion/ruby-example-app:chore/ci', - databases: ['PostgreSQL'], - user_roles: [] - }, - poolSize: +process.env.SECTESTER_SCAN_POOL_SIZE || undefined - }) - .setFailFast(false) - .timeout(timeout) - .run({ - method: HttpMethod.PATCH, - url: `${baseUrl}/users/123.json`, - body: { - email: 'user@example.com', - password: 'securepassword', - password_digest: '$2a$12$KIXQ1Y1rZ1u1u1u1u1u1uO', - admin: false - }, - headers: { 'Content-Type': 'application/json' } - }); -}); From 1ec41d6eb7539c3c06bb8c572c2c29f87921f1f2 Mon Sep 17 00:00:00 2001 From: Viachaslau Date: Wed, 18 Feb 2026 00:22:35 +0400 Subject: [PATCH 17/18] test: optimize security tests to focus on specific vulnerabilities skip-checks:true From e36a3d93f95a57ef5159e43ff99260c098cbbf24 Mon Sep 17 00:00:00 2001 From: Viachaslau Date: Wed, 18 Feb 2026 00:23:00 +0400 Subject: [PATCH 18/18] fix: apply automated fixes for detected vulnerabilities --- app/controllers/posts_controller.rb | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/controllers/posts_controller.rb b/app/controllers/posts_controller.rb index 2892213..fdad750 100644 --- a/app/controllers/posts_controller.rb +++ b/app/controllers/posts_controller.rb @@ -30,9 +30,9 @@ def recent def search # http://localhost:3000/posts/search?search_term=t%25%27%3Bselect%20*%20from%20users%3B%20-- if current_user.admin? - @search_results = Post.where("posts.content::text LIKE '%#{params[:search_term]}%'") + @search_results = Post.where("posts.content::text LIKE ?", "%#{params[:search_term]}%") else - @search_results = Post.where("posts.content::text LIKE '%#{params[:search_term]}%' AND posts.public=true") + @search_results = Post.where("posts.content::text LIKE ? AND posts.public=true", "%#{params[:search_term]}%") end end