refactor: rename sec_dashboard to bulwark
Rename the entire project from SecDashboard to Bulwark: - Module prefixes: SecDashboard -> Bulwark, SecDashboardWeb -> BulwarkWeb - OTP app atom: :sec_dashboard -> :bulwark - Directory structure: lib/sec_dashboard -> lib/bulwark, etc - Config, assets, tests, migrations all updated - Database names: bulwark_dev, bulwark_test
This commit is contained in:
@@ -23,15 +23,15 @@ mix precommit # Pre-commit gate: compile --warning-as-errors, deps.
|
||||
|
||||
Phoenix 1.8 app with LiveView 1.1, PostgreSQL (Ecto), Bandit HTTP server.
|
||||
|
||||
- `lib/sec_dashboard/` — business logic (domain layer). `Repo` uses `Ecto.Adapters.Postgres`.
|
||||
- `lib/sec_dashboard_web/` — web layer. Router, endpoint, LiveViews, components.
|
||||
- `SecDashboardWeb` (`lib/sec_dashboard_web.ex`) — macro module that defines `use SecDashboardWeb, :live_view` etc. `html_helpers/0` auto-imports `CoreComponents`, aliases `Layouts` and `Phoenix.LiveView.JS`.
|
||||
- `lib/bulwark/` — business logic (domain layer). `Repo` uses `Ecto.Adapters.Postgres`.
|
||||
- `lib/bulwark_web/` — web layer. Router, endpoint, LiveViews, components.
|
||||
- `BulwarkWeb` (`lib/bulwark_web.ex`) — macro module that defines `use BulwarkWeb, :live_view` etc. `html_helpers/0` auto-imports `CoreComponents`, aliases `Layouts` and `Phoenix.LiveView.JS`.
|
||||
- `config/` — `config.exs` (shared) -> `dev.exs`/`test.exs`/`prod.exs` -> `runtime.exs`.
|
||||
|
||||
### Bounded Contexts
|
||||
|
||||
- **`SecDashboard.Security`** — domain context. Schemas: `Scan`, `Asset`, `Vulnerability`, `Finding`. CRUD with Flop-powered queries. Assets and Vulnerabilities use upsert (conflict on unique keys). Triage via `update_finding_status/2` with PubSub broadcast.
|
||||
- **`SecDashboard.Ingestion`** — pipeline context. `ParseJob` (Oban worker), `Detector` (format/tool identification), and `Parsers` (Trivy, SARIF, CycloneDX, Grype, Snyk) that normalize diverse tool outputs into the Security domain. SPDX BOMs are detected but produce zero findings (BOM-only format). Scans can be cancelled while pending/processing.
|
||||
- **`Bulwark.Security`** — domain context. Schemas: `Scan`, `Asset`, `Vulnerability`, `Finding`. CRUD with Flop-powered queries. Assets and Vulnerabilities use upsert (conflict on unique keys). Triage via `update_finding_status/2` with PubSub broadcast.
|
||||
- **`Bulwark.Ingestion`** — pipeline context. `ParseJob` (Oban worker), `Detector` (format/tool identification), and `Parsers` (Trivy, SARIF, CycloneDX, Grype, Snyk) that normalize diverse tool outputs into the Security domain. SPDX BOMs are detected but produce zero findings (BOM-only format). Scans can be cancelled while pending/processing.
|
||||
|
||||
### Ingestion Pipeline
|
||||
|
||||
|
||||
@@ -24,7 +24,7 @@ Built with Phoenix 1.8, LiveView 1.1, PostgreSQL, and Oban.
|
||||
|
||||
```bash
|
||||
# Clone the repository
|
||||
git clone <repo-url> && cd sec_dashboard
|
||||
git clone <repo-url> && cd bulwark
|
||||
|
||||
# Start PostgreSQL
|
||||
docker compose up -d
|
||||
@@ -58,12 +58,12 @@ Runs `compile --warnings-as-errors`, `deps.unlock --check-unused`, `format --che
|
||||
|
||||
```
|
||||
lib/
|
||||
├── sec_dashboard/ # Domain layer
|
||||
├── bulwark/ # Domain layer
|
||||
│ ├── security.ex # Security context — CRUD, queries, triage
|
||||
│ ├── security/ # Schemas: Scan, Asset, Vulnerability, Finding
|
||||
│ ├── ingestion/ # Pipeline: Detector, ParseJob (Oban), Parsers
|
||||
│ └── repo.ex
|
||||
└── sec_dashboard_web/ # Web layer
|
||||
└── bulwark_web/ # Web layer
|
||||
├── components/ # CoreComponents, Layouts (sidebar shell)
|
||||
├── live/ # LiveViews for each route
|
||||
├── router.ex
|
||||
@@ -74,8 +74,8 @@ lib/
|
||||
|
||||
| Context | Purpose |
|
||||
|---------|---------|
|
||||
| `SecDashboard.Security` | Domain CRUD, Flop queries, upserts, triage with PubSub |
|
||||
| `SecDashboard.Ingestion` | Format detection, parsing, Oban job orchestration |
|
||||
| `Bulwark.Security` | Domain CRUD, Flop queries, upserts, triage with PubSub |
|
||||
| `Bulwark.Ingestion` | Format detection, parsing, Oban job orchestration |
|
||||
|
||||
### Ingestion Pipeline
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
@import "tailwindcss" source(none);
|
||||
@source "../css";
|
||||
@source "../js";
|
||||
@source "../../lib/sec_dashboard_web";
|
||||
@source "../../lib/bulwark_web";
|
||||
|
||||
@plugin "../vendor/heroicons";
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
import "phoenix_html"
|
||||
import {Socket} from "phoenix"
|
||||
import {LiveSocket} from "phoenix_live_view"
|
||||
import {hooks as colocatedHooks} from "phoenix-colocated/sec_dashboard"
|
||||
import {hooks as colocatedHooks} from "phoenix-colocated/bulwark"
|
||||
import topbar from "../vendor/topbar"
|
||||
|
||||
const Sidebar = {
|
||||
|
||||
+12
-12
@@ -7,19 +7,19 @@
|
||||
# General application configuration
|
||||
import Config
|
||||
|
||||
config :sec_dashboard,
|
||||
ecto_repos: [SecDashboard.Repo],
|
||||
config :bulwark,
|
||||
ecto_repos: [Bulwark.Repo],
|
||||
generators: [timestamp_type: :utc_datetime]
|
||||
|
||||
# Configures the endpoint
|
||||
config :sec_dashboard, SecDashboardWeb.Endpoint,
|
||||
config :bulwark, BulwarkWeb.Endpoint,
|
||||
url: [host: "localhost"],
|
||||
adapter: Bandit.PhoenixAdapter,
|
||||
render_errors: [
|
||||
formats: [html: SecDashboardWeb.ErrorHTML, json: SecDashboardWeb.ErrorJSON],
|
||||
formats: [html: BulwarkWeb.ErrorHTML, json: BulwarkWeb.ErrorJSON],
|
||||
layout: false
|
||||
],
|
||||
pubsub_server: SecDashboard.PubSub,
|
||||
pubsub_server: Bulwark.PubSub,
|
||||
live_view: [signing_salt: "4uP78Fmk"]
|
||||
|
||||
# Configures the mailer
|
||||
@@ -29,12 +29,12 @@ config :sec_dashboard, SecDashboardWeb.Endpoint,
|
||||
#
|
||||
# For production it's recommended to configure a different adapter
|
||||
# at the `config/runtime.exs`.
|
||||
config :sec_dashboard, SecDashboard.Mailer, adapter: Swoosh.Adapters.Local
|
||||
config :bulwark, Bulwark.Mailer, adapter: Swoosh.Adapters.Local
|
||||
|
||||
# Configure esbuild (the version is required)
|
||||
config :esbuild,
|
||||
version: "0.25.4",
|
||||
sec_dashboard: [
|
||||
bulwark: [
|
||||
args:
|
||||
~w(js/app.js --bundle --target=es2022 --outdir=../priv/static/assets/js --external:/fonts/* --external:/images/* --alias:@=.),
|
||||
cd: Path.expand("../assets", __DIR__),
|
||||
@@ -44,7 +44,7 @@ config :esbuild,
|
||||
# Configure tailwind (the version is required)
|
||||
config :tailwind,
|
||||
version: "4.1.7",
|
||||
sec_dashboard: [
|
||||
bulwark: [
|
||||
args: ~w(
|
||||
--input=assets/css/app.css
|
||||
--output=priv/static/assets/css/app.css
|
||||
@@ -62,13 +62,13 @@ config :mime, :types, %{"application/sarif+json" => ["sarif"]}
|
||||
# Use Jason for JSON parsing in Phoenix
|
||||
config :phoenix, :json_library, Jason
|
||||
|
||||
config :sec_dashboard, Oban,
|
||||
repo: SecDashboard.Repo,
|
||||
config :bulwark, Oban,
|
||||
repo: Bulwark.Repo,
|
||||
queues: [ingestion: 4]
|
||||
|
||||
config :flop, repo: SecDashboard.Repo
|
||||
config :flop, repo: Bulwark.Repo
|
||||
|
||||
config :sec_dashboard, :upload_dir, Path.expand("../priv/uploads", __DIR__)
|
||||
config :bulwark, :upload_dir, Path.expand("../priv/uploads", __DIR__)
|
||||
|
||||
# Import environment specific config. This must remain at the bottom
|
||||
# of this file so it overrides the configuration defined above.
|
||||
|
||||
+8
-8
@@ -1,11 +1,11 @@
|
||||
import Config
|
||||
|
||||
# Configure your database
|
||||
config :sec_dashboard, SecDashboard.Repo,
|
||||
config :bulwark, Bulwark.Repo,
|
||||
username: "postgres",
|
||||
password: "postgres",
|
||||
hostname: "localhost",
|
||||
database: "sec_dashboard_dev",
|
||||
database: "bulwark_dev",
|
||||
stacktrace: true,
|
||||
show_sensitive_data_on_connection_error: true,
|
||||
pool_size: 10
|
||||
@@ -16,7 +16,7 @@ config :sec_dashboard, SecDashboard.Repo,
|
||||
# The watchers configuration can be used to run external
|
||||
# watchers to your application. For example, we can use it
|
||||
# to bundle .js and .css sources.
|
||||
config :sec_dashboard, SecDashboardWeb.Endpoint,
|
||||
config :bulwark, BulwarkWeb.Endpoint,
|
||||
# Binding to loopback ipv4 address prevents access from other machines.
|
||||
# Change to `ip: {0, 0, 0, 0}` to allow access from other machines.
|
||||
http: [ip: {127, 0, 0, 1}, port: String.to_integer(System.get_env("PORT") || "4000")],
|
||||
@@ -25,8 +25,8 @@ config :sec_dashboard, SecDashboardWeb.Endpoint,
|
||||
debug_errors: true,
|
||||
secret_key_base: "ZYZsEiZrHZBajKTr+Cf8d+M77eqAmPXMDGj8GqWYvTnXa2aMAKf/32QW6I/xcO8x",
|
||||
watchers: [
|
||||
esbuild: {Esbuild, :install_and_run, [:sec_dashboard, ~w(--sourcemap=inline --watch)]},
|
||||
tailwind: {Tailwind, :install_and_run, [:sec_dashboard, ~w(--watch)]}
|
||||
esbuild: {Esbuild, :install_and_run, [:bulwark, ~w(--sourcemap=inline --watch)]},
|
||||
tailwind: {Tailwind, :install_and_run, [:bulwark, ~w(--watch)]}
|
||||
]
|
||||
|
||||
# ## SSL Support
|
||||
@@ -53,18 +53,18 @@ config :sec_dashboard, SecDashboardWeb.Endpoint,
|
||||
# different ports.
|
||||
|
||||
# Watch static and templates for browser reloading.
|
||||
config :sec_dashboard, SecDashboardWeb.Endpoint,
|
||||
config :bulwark, BulwarkWeb.Endpoint,
|
||||
live_reload: [
|
||||
web_console_logger: true,
|
||||
patterns: [
|
||||
~r"priv/static/(?!uploads/).*(js|css|png|jpeg|jpg|gif|svg)$",
|
||||
~r"priv/gettext/.*(po)$",
|
||||
~r"lib/sec_dashboard_web/(?:controllers|live|components|router)/?.*\.(ex|heex)$"
|
||||
~r"lib/bulwark_web/(?:controllers|live|components|router)/?.*\.(ex|heex)$"
|
||||
]
|
||||
]
|
||||
|
||||
# Enable dev routes for dashboard and mailbox
|
||||
config :sec_dashboard, dev_routes: true
|
||||
config :bulwark, dev_routes: true
|
||||
|
||||
# Do not include metadata nor timestamps in development logs
|
||||
config :logger, :default_formatter, format: "[$level] $message\n"
|
||||
|
||||
+1
-2
@@ -5,8 +5,7 @@ import Config
|
||||
# manifest is generated by the `mix assets.deploy` task,
|
||||
# which you should run after static files are built and
|
||||
# before starting your production server.
|
||||
config :sec_dashboard, SecDashboardWeb.Endpoint,
|
||||
cache_static_manifest: "priv/static/cache_manifest.json"
|
||||
config :bulwark, BulwarkWeb.Endpoint, cache_static_manifest: "priv/static/cache_manifest.json"
|
||||
|
||||
# Configures Swoosh API Client
|
||||
config :swoosh, api_client: Swoosh.ApiClient.Req
|
||||
|
||||
+8
-8
@@ -12,12 +12,12 @@ import Config
|
||||
# If you use `mix release`, you need to explicitly enable the server
|
||||
# by passing the PHX_SERVER=true when you start it:
|
||||
#
|
||||
# PHX_SERVER=true bin/sec_dashboard start
|
||||
# PHX_SERVER=true bin/bulwark start
|
||||
#
|
||||
# Alternatively, you can use `mix phx.gen.release` to generate a `bin/server`
|
||||
# script that automatically sets the env var above.
|
||||
if System.get_env("PHX_SERVER") do
|
||||
config :sec_dashboard, SecDashboardWeb.Endpoint, server: true
|
||||
config :bulwark, BulwarkWeb.Endpoint, server: true
|
||||
end
|
||||
|
||||
if config_env() == :prod do
|
||||
@@ -30,7 +30,7 @@ if config_env() == :prod do
|
||||
|
||||
maybe_ipv6 = if System.get_env("ECTO_IPV6") in ~w(true 1), do: [:inet6], else: []
|
||||
|
||||
config :sec_dashboard, SecDashboard.Repo,
|
||||
config :bulwark, Bulwark.Repo,
|
||||
url: database_url,
|
||||
pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10"),
|
||||
socket_options: maybe_ipv6
|
||||
@@ -50,9 +50,9 @@ if config_env() == :prod do
|
||||
host = System.get_env("PHX_HOST") || "example.com"
|
||||
port = String.to_integer(System.get_env("PORT") || "4000")
|
||||
|
||||
config :sec_dashboard, :dns_cluster_query, System.get_env("DNS_CLUSTER_QUERY")
|
||||
config :bulwark, :dns_cluster_query, System.get_env("DNS_CLUSTER_QUERY")
|
||||
|
||||
config :sec_dashboard, SecDashboardWeb.Endpoint,
|
||||
config :bulwark, BulwarkWeb.Endpoint,
|
||||
url: [host: host, port: 443, scheme: "https"],
|
||||
http: [
|
||||
# Enable IPv6 and bind on all interfaces.
|
||||
@@ -69,7 +69,7 @@ if config_env() == :prod do
|
||||
# To get SSL working, you will need to add the `https` key
|
||||
# to your endpoint configuration:
|
||||
#
|
||||
# config :sec_dashboard, SecDashboardWeb.Endpoint,
|
||||
# config :bulwark, BulwarkWeb.Endpoint,
|
||||
# https: [
|
||||
# ...,
|
||||
# port: 443,
|
||||
@@ -91,7 +91,7 @@ if config_env() == :prod do
|
||||
# We also recommend setting `force_ssl` in your config/prod.exs,
|
||||
# ensuring no data is ever sent via http, always redirecting to https:
|
||||
#
|
||||
# config :sec_dashboard, SecDashboardWeb.Endpoint,
|
||||
# config :bulwark, BulwarkWeb.Endpoint,
|
||||
# force_ssl: [hsts: true]
|
||||
#
|
||||
# Check `Plug.SSL` for all available options in `force_ssl`.
|
||||
@@ -101,7 +101,7 @@ if config_env() == :prod do
|
||||
# In production you need to configure the mailer to use a different adapter.
|
||||
# Here is an example configuration for Mailgun:
|
||||
#
|
||||
# config :sec_dashboard, SecDashboard.Mailer,
|
||||
# config :bulwark, Bulwark.Mailer,
|
||||
# adapter: Swoosh.Adapters.Mailgun,
|
||||
# api_key: System.get_env("MAILGUN_API_KEY"),
|
||||
# domain: System.get_env("MAILGUN_DOMAIN")
|
||||
|
||||
+5
-5
@@ -5,23 +5,23 @@ import Config
|
||||
# The MIX_TEST_PARTITION environment variable can be used
|
||||
# to provide built-in test partitioning in CI environment.
|
||||
# Run `mix help test` for more information.
|
||||
config :sec_dashboard, SecDashboard.Repo,
|
||||
config :bulwark, Bulwark.Repo,
|
||||
username: "postgres",
|
||||
password: "postgres",
|
||||
hostname: "localhost",
|
||||
database: "sec_dashboard_test#{System.get_env("MIX_TEST_PARTITION")}",
|
||||
database: "bulwark_test#{System.get_env("MIX_TEST_PARTITION")}",
|
||||
pool: Ecto.Adapters.SQL.Sandbox,
|
||||
pool_size: String.to_integer(System.get_env("POOL_SIZE") || "10")
|
||||
|
||||
# We don't run a server during test. If one is required,
|
||||
# you can enable the server option below.
|
||||
config :sec_dashboard, SecDashboardWeb.Endpoint,
|
||||
config :bulwark, BulwarkWeb.Endpoint,
|
||||
http: [ip: {127, 0, 0, 1}, port: 4002],
|
||||
secret_key_base: "eY3kwD7MW/KzmXoW8XsEU//xv9WLQT3hBSAp9NGXJNyiq1LgS/cDfSfzAqn4B4jQ",
|
||||
server: false
|
||||
|
||||
# In test we don't send emails
|
||||
config :sec_dashboard, SecDashboard.Mailer, adapter: Swoosh.Adapters.Test
|
||||
config :bulwark, Bulwark.Mailer, adapter: Swoosh.Adapters.Test
|
||||
|
||||
# Disable swoosh api client as it is only required for production adapters
|
||||
config :swoosh, :api_client, false
|
||||
@@ -29,7 +29,7 @@ config :swoosh, :api_client, false
|
||||
# Print only warnings and errors during test
|
||||
config :logger, level: :warning
|
||||
|
||||
config :sec_dashboard, Oban, testing: :manual
|
||||
config :bulwark, Oban, testing: :manual
|
||||
|
||||
# Initialize plugs at runtime for faster test compilation
|
||||
config :phoenix, :plug_init_mode, :runtime
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
defmodule SecDashboard do
|
||||
defmodule Bulwark do
|
||||
@moduledoc """
|
||||
SecDashboard keeps the contexts that define your domain
|
||||
Bulwark keeps the contexts that define your domain
|
||||
and business logic.
|
||||
|
||||
Contexts are also responsible for managing your data, regardless
|
||||
@@ -1,4 +1,4 @@
|
||||
defmodule SecDashboard.Application do
|
||||
defmodule Bulwark.Application do
|
||||
# See https://hexdocs.pm/elixir/Application.html
|
||||
# for more information on OTP Applications
|
||||
@moduledoc false
|
||||
@@ -8,17 +8,17 @@ defmodule SecDashboard.Application do
|
||||
@impl true
|
||||
def start(_type, _args) do
|
||||
children = [
|
||||
SecDashboardWeb.Telemetry,
|
||||
SecDashboard.Repo,
|
||||
{DNSCluster, query: Application.get_env(:sec_dashboard, :dns_cluster_query) || :ignore},
|
||||
{Phoenix.PubSub, name: SecDashboard.PubSub},
|
||||
{Oban, Application.fetch_env!(:sec_dashboard, Oban)},
|
||||
SecDashboardWeb.Endpoint
|
||||
BulwarkWeb.Telemetry,
|
||||
Bulwark.Repo,
|
||||
{DNSCluster, query: Application.get_env(:bulwark, :dns_cluster_query) || :ignore},
|
||||
{Phoenix.PubSub, name: Bulwark.PubSub},
|
||||
{Oban, Application.fetch_env!(:bulwark, Oban)},
|
||||
BulwarkWeb.Endpoint
|
||||
]
|
||||
|
||||
# See https://hexdocs.pm/elixir/Supervisor.html
|
||||
# for other strategies and supported options
|
||||
opts = [strategy: :one_for_one, name: SecDashboard.Supervisor]
|
||||
opts = [strategy: :one_for_one, name: Bulwark.Supervisor]
|
||||
Supervisor.start_link(children, opts)
|
||||
end
|
||||
|
||||
@@ -26,7 +26,7 @@ defmodule SecDashboard.Application do
|
||||
# whenever the application is updated.
|
||||
@impl true
|
||||
def config_change(changed, _new, removed) do
|
||||
SecDashboardWeb.Endpoint.config_change(changed, removed)
|
||||
BulwarkWeb.Endpoint.config_change(changed, removed)
|
||||
:ok
|
||||
end
|
||||
end
|
||||
@@ -1,4 +1,4 @@
|
||||
defmodule SecDashboard.Ingestion.Detector do
|
||||
defmodule Bulwark.Ingestion.Detector do
|
||||
@moduledoc """
|
||||
Identifies the source tool and format of a parsed security artifact.
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
defmodule SecDashboard.Ingestion.ParseJob do
|
||||
defmodule Bulwark.Ingestion.ParseJob do
|
||||
@moduledoc """
|
||||
Oban worker that processes uploaded security artifacts.
|
||||
|
||||
@@ -9,10 +9,10 @@ defmodule SecDashboard.Ingestion.ParseJob do
|
||||
"""
|
||||
use Oban.Worker, queue: :ingestion, max_attempts: 3
|
||||
|
||||
alias SecDashboard.{Repo, Security}
|
||||
alias SecDashboard.Ingestion.{Detector, Parsers}
|
||||
alias Bulwark.{Repo, Security}
|
||||
alias Bulwark.Ingestion.{Detector, Parsers}
|
||||
|
||||
@pubsub SecDashboard.PubSub
|
||||
@pubsub Bulwark.PubSub
|
||||
|
||||
@impl Oban.Worker
|
||||
def perform(%Oban.Job{args: %{"scan_id" => scan_id}}) do
|
||||
@@ -1,10 +1,10 @@
|
||||
defmodule SecDashboard.Ingestion.Parser do
|
||||
defmodule Bulwark.Ingestion.Parser do
|
||||
@moduledoc """
|
||||
Behaviour for security scan parsers.
|
||||
|
||||
Each parser implementation accepts a decoded JSON map from a specific tool
|
||||
or format and returns a list of normalized findings that can be persisted
|
||||
into the `SecDashboard.Security` domain.
|
||||
into the `Bulwark.Security` domain.
|
||||
"""
|
||||
|
||||
@typedoc """
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
defmodule SecDashboard.Ingestion.Parsers.CycloneDX do
|
||||
defmodule Bulwark.Ingestion.Parsers.CycloneDX do
|
||||
@moduledoc """
|
||||
Parser for CycloneDX BOM JSON reports.
|
||||
|
||||
@@ -6,7 +6,7 @@ defmodule SecDashboard.Ingestion.Parsers.CycloneDX do
|
||||
component index (by purl, bom-ref, or name) to resolve affected packages
|
||||
and their versions.
|
||||
"""
|
||||
@behaviour SecDashboard.Ingestion.Parser
|
||||
@behaviour Bulwark.Ingestion.Parser
|
||||
|
||||
@impl true
|
||||
def parse(%{"bomFormat" => "CycloneDX"} = bom) do
|
||||
+3
-3
@@ -1,12 +1,12 @@
|
||||
defmodule SecDashboard.Ingestion.Parsers.Grype do
|
||||
defmodule Bulwark.Ingestion.Parsers.Grype do
|
||||
@moduledoc """
|
||||
Parser for Anchore Grype JSON scan reports.
|
||||
|
||||
Normalizes Grype's `matches` array into `t:SecDashboard.Ingestion.Parser.normalized_finding/0`
|
||||
Normalizes Grype's `matches` array into `t:Bulwark.Ingestion.Parser.normalized_finding/0`
|
||||
maps, extracting vulnerability IDs, severity, affected packages, and fix versions
|
||||
from the Grype-specific match/artifact structure.
|
||||
"""
|
||||
@behaviour SecDashboard.Ingestion.Parser
|
||||
@behaviour Bulwark.Ingestion.Parser
|
||||
|
||||
@impl true
|
||||
def parse(%{"matches" => matches} = report) when is_list(matches) do
|
||||
+2
-2
@@ -1,4 +1,4 @@
|
||||
defmodule SecDashboard.Ingestion.Parsers.Sarif do
|
||||
defmodule Bulwark.Ingestion.Parsers.Sarif do
|
||||
@moduledoc """
|
||||
Parser for SARIF v2.1.0 static analysis reports.
|
||||
|
||||
@@ -6,7 +6,7 @@ defmodule SecDashboard.Ingestion.Parsers.Sarif do
|
||||
Maps SARIF severity levels (error, warning, note) to normalized severities
|
||||
and extracts file locations, rule IDs, and help URIs.
|
||||
"""
|
||||
@behaviour SecDashboard.Ingestion.Parser
|
||||
@behaviour Bulwark.Ingestion.Parser
|
||||
|
||||
@impl true
|
||||
def parse(%{"runs" => runs}) when is_list(runs) do
|
||||
@@ -1,12 +1,12 @@
|
||||
defmodule SecDashboard.Ingestion.Parsers.Snyk do
|
||||
defmodule Bulwark.Ingestion.Parsers.Snyk do
|
||||
@moduledoc """
|
||||
Parser for Snyk JSON test output (`snyk test --json`).
|
||||
|
||||
Normalizes Snyk's `vulnerabilities` array into
|
||||
`t:SecDashboard.Ingestion.Parser.normalized_finding/0` maps, extracting
|
||||
`t:Bulwark.Ingestion.Parser.normalized_finding/0` maps, extracting
|
||||
CVE/SNYK IDs, severity, upgrade paths, and package version info.
|
||||
"""
|
||||
@behaviour SecDashboard.Ingestion.Parser
|
||||
@behaviour Bulwark.Ingestion.Parser
|
||||
|
||||
@impl true
|
||||
def parse(%{"vulnerabilities" => vulns} = report) when is_list(vulns) do
|
||||
+3
-3
@@ -1,11 +1,11 @@
|
||||
defmodule SecDashboard.Ingestion.Parsers.Trivy do
|
||||
defmodule Bulwark.Ingestion.Parsers.Trivy do
|
||||
@moduledoc """
|
||||
Parser for Trivy JSON v2 scan reports.
|
||||
|
||||
Normalizes Trivy's `Results` array into `t:SecDashboard.Ingestion.Parser.normalized_finding/0`
|
||||
Normalizes Trivy's `Results` array into `t:Bulwark.Ingestion.Parser.normalized_finding/0`
|
||||
maps, extracting vulnerability IDs, severity, affected packages, and version info.
|
||||
"""
|
||||
@behaviour SecDashboard.Ingestion.Parser
|
||||
@behaviour Bulwark.Ingestion.Parser
|
||||
|
||||
@impl true
|
||||
def parse(%{"Results" => results} = report) do
|
||||
@@ -0,0 +1,3 @@
|
||||
defmodule Bulwark.Mailer do
|
||||
use Swoosh.Mailer, otp_app: :bulwark
|
||||
end
|
||||
@@ -0,0 +1,5 @@
|
||||
defmodule Bulwark.Repo do
|
||||
use Ecto.Repo,
|
||||
otp_app: :bulwark,
|
||||
adapter: Ecto.Adapters.Postgres
|
||||
end
|
||||
@@ -1,4 +1,4 @@
|
||||
defmodule SecDashboard.Security do
|
||||
defmodule Bulwark.Security do
|
||||
@moduledoc """
|
||||
The Security context manages scans, assets, vulnerabilities, and findings.
|
||||
|
||||
@@ -9,8 +9,8 @@ defmodule SecDashboard.Security do
|
||||
|
||||
import Ecto.Query
|
||||
|
||||
alias SecDashboard.Repo
|
||||
alias SecDashboard.Security.{Scan, Asset, Vulnerability, Finding}
|
||||
alias Bulwark.Repo
|
||||
alias Bulwark.Security.{Scan, Asset, Vulnerability, Finding}
|
||||
|
||||
# --- Scans ---
|
||||
|
||||
@@ -76,8 +76,8 @@ defmodule SecDashboard.Security do
|
||||
@spec cancel_scan(Scan.t()) :: {:ok, Scan.t()} | {:error, :not_cancellable}
|
||||
def cancel_scan(%Scan{status: status} = scan) when status in ~w(pending processing) do
|
||||
{:ok, scan} = update_scan_status(scan, "cancelled", %{completed_at: DateTime.utc_now()})
|
||||
Phoenix.PubSub.broadcast(SecDashboard.PubSub, "scans", {:scan_updated, scan})
|
||||
Phoenix.PubSub.broadcast(SecDashboard.PubSub, "scan:#{scan.id}", {:scan_updated, scan})
|
||||
Phoenix.PubSub.broadcast(Bulwark.PubSub, "scans", {:scan_updated, scan})
|
||||
Phoenix.PubSub.broadcast(Bulwark.PubSub, "scan:#{scan.id}", {:scan_updated, scan})
|
||||
{:ok, scan}
|
||||
end
|
||||
|
||||
@@ -262,7 +262,7 @@ defmodule SecDashboard.Security do
|
||||
|
||||
case result do
|
||||
{:ok, updated} ->
|
||||
Phoenix.PubSub.broadcast(SecDashboard.PubSub, "findings", {:finding_updated, updated})
|
||||
Phoenix.PubSub.broadcast(Bulwark.PubSub, "findings", {:finding_updated, updated})
|
||||
{:ok, updated}
|
||||
|
||||
error ->
|
||||
@@ -1,4 +1,4 @@
|
||||
defmodule SecDashboard.Security.Asset do
|
||||
defmodule Bulwark.Security.Asset do
|
||||
@moduledoc """
|
||||
Represents a discoverable asset such as a container image, package, repository,
|
||||
or filesystem.
|
||||
@@ -22,7 +22,7 @@ defmodule SecDashboard.Security.Asset do
|
||||
field :identifier, :string
|
||||
field :metadata, :map, default: %{}
|
||||
|
||||
has_many :findings, SecDashboard.Security.Finding
|
||||
has_many :findings, Bulwark.Security.Finding
|
||||
|
||||
timestamps(type: :utc_datetime)
|
||||
end
|
||||
@@ -1,4 +1,4 @@
|
||||
defmodule SecDashboard.Security.Finding do
|
||||
defmodule Bulwark.Security.Finding do
|
||||
@moduledoc """
|
||||
Represents an individual finding linking a scan to a vulnerability and asset.
|
||||
|
||||
@@ -23,9 +23,9 @@ defmodule SecDashboard.Security.Finding do
|
||||
field :status, :string, default: "open"
|
||||
field :raw_data, :map, default: %{}
|
||||
|
||||
belongs_to :scan, SecDashboard.Security.Scan
|
||||
belongs_to :vulnerability, SecDashboard.Security.Vulnerability
|
||||
belongs_to :asset, SecDashboard.Security.Asset
|
||||
belongs_to :scan, Bulwark.Security.Scan
|
||||
belongs_to :vulnerability, Bulwark.Security.Vulnerability
|
||||
belongs_to :asset, Bulwark.Security.Asset
|
||||
|
||||
timestamps(type: :utc_datetime)
|
||||
end
|
||||
@@ -1,4 +1,4 @@
|
||||
defmodule SecDashboard.Security.Scan do
|
||||
defmodule Bulwark.Security.Scan do
|
||||
@moduledoc """
|
||||
Represents a security scan ingestion run.
|
||||
|
||||
@@ -27,7 +27,7 @@ defmodule SecDashboard.Security.Scan do
|
||||
field :started_at, :utc_datetime
|
||||
field :completed_at, :utc_datetime
|
||||
|
||||
has_many :findings, SecDashboard.Security.Finding
|
||||
has_many :findings, Bulwark.Security.Finding
|
||||
|
||||
timestamps(type: :utc_datetime)
|
||||
end
|
||||
@@ -1,4 +1,4 @@
|
||||
defmodule SecDashboard.Security.Vulnerability do
|
||||
defmodule Bulwark.Security.Vulnerability do
|
||||
@moduledoc """
|
||||
Represents a unique vulnerability identified by its `external_id` (e.g., CVE ID).
|
||||
|
||||
@@ -32,7 +32,7 @@ defmodule SecDashboard.Security.Vulnerability do
|
||||
field :description, :string
|
||||
field :references, {:array, :string}, default: []
|
||||
|
||||
has_many :findings, SecDashboard.Security.Finding
|
||||
has_many :findings, Bulwark.Security.Finding
|
||||
|
||||
timestamps(type: :utc_datetime)
|
||||
end
|
||||
@@ -1,12 +1,12 @@
|
||||
defmodule SecDashboardWeb do
|
||||
defmodule BulwarkWeb do
|
||||
@moduledoc """
|
||||
The entrypoint for defining your web interface, such
|
||||
as controllers, components, channels, and so on.
|
||||
|
||||
This can be used in your application as:
|
||||
|
||||
use SecDashboardWeb, :controller
|
||||
use SecDashboardWeb, :html
|
||||
use BulwarkWeb, :controller
|
||||
use BulwarkWeb, :html
|
||||
|
||||
The definitions below will be executed for every controller,
|
||||
component, etc, so keep them short and clean, focused
|
||||
@@ -40,7 +40,7 @@ defmodule SecDashboardWeb do
|
||||
quote do
|
||||
use Phoenix.Controller, formats: [:html, :json]
|
||||
|
||||
use Gettext, backend: SecDashboardWeb.Gettext
|
||||
use Gettext, backend: BulwarkWeb.Gettext
|
||||
|
||||
import Plug.Conn
|
||||
|
||||
@@ -80,16 +80,16 @@ defmodule SecDashboardWeb do
|
||||
defp html_helpers do
|
||||
quote do
|
||||
# Translation
|
||||
use Gettext, backend: SecDashboardWeb.Gettext
|
||||
use Gettext, backend: BulwarkWeb.Gettext
|
||||
|
||||
# HTML escaping functionality
|
||||
import Phoenix.HTML
|
||||
# Core UI components
|
||||
import SecDashboardWeb.CoreComponents
|
||||
import BulwarkWeb.CoreComponents
|
||||
|
||||
# Common modules used in templates
|
||||
alias Phoenix.LiveView.JS
|
||||
alias SecDashboardWeb.Layouts
|
||||
alias BulwarkWeb.Layouts
|
||||
|
||||
# Routes generation with the ~p sigil
|
||||
unquote(verified_routes())
|
||||
@@ -99,9 +99,9 @@ defmodule SecDashboardWeb do
|
||||
def verified_routes do
|
||||
quote do
|
||||
use Phoenix.VerifiedRoutes,
|
||||
endpoint: SecDashboardWeb.Endpoint,
|
||||
router: SecDashboardWeb.Router,
|
||||
statics: SecDashboardWeb.static_paths()
|
||||
endpoint: BulwarkWeb.Endpoint,
|
||||
router: BulwarkWeb.Router,
|
||||
statics: BulwarkWeb.static_paths()
|
||||
end
|
||||
end
|
||||
|
||||
+4
-4
@@ -1,4 +1,4 @@
|
||||
defmodule SecDashboardWeb.CoreComponents do
|
||||
defmodule BulwarkWeb.CoreComponents do
|
||||
@moduledoc """
|
||||
Provides core UI components.
|
||||
|
||||
@@ -12,7 +12,7 @@ defmodule SecDashboardWeb.CoreComponents do
|
||||
|
||||
"""
|
||||
use Phoenix.Component
|
||||
use Gettext, backend: SecDashboardWeb.Gettext
|
||||
use Gettext, backend: BulwarkWeb.Gettext
|
||||
|
||||
alias Phoenix.LiveView.JS
|
||||
|
||||
@@ -451,9 +451,9 @@ defmodule SecDashboardWeb.CoreComponents do
|
||||
"""
|
||||
def translate_error({msg, opts}) do
|
||||
if count = opts[:count] do
|
||||
Gettext.dngettext(SecDashboardWeb.Gettext, "errors", msg, msg, count, opts)
|
||||
Gettext.dngettext(BulwarkWeb.Gettext, "errors", msg, msg, count, opts)
|
||||
else
|
||||
Gettext.dgettext(SecDashboardWeb.Gettext, "errors", msg, opts)
|
||||
Gettext.dgettext(BulwarkWeb.Gettext, "errors", msg, opts)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
defmodule SecDashboardWeb.Layouts do
|
||||
defmodule BulwarkWeb.Layouts do
|
||||
@moduledoc """
|
||||
Layout components for the application shell.
|
||||
|
||||
@@ -7,7 +7,7 @@ defmodule SecDashboardWeb.Layouts do
|
||||
The sidebar is 52px collapsed / 180px expanded on desktop, and slides in as
|
||||
a full-width overlay on mobile.
|
||||
"""
|
||||
use SecDashboardWeb, :html
|
||||
use BulwarkWeb, :html
|
||||
|
||||
embed_templates "layouts/*"
|
||||
|
||||
+4
-4
@@ -1,17 +1,17 @@
|
||||
defmodule SecDashboardWeb.ErrorHTML do
|
||||
defmodule BulwarkWeb.ErrorHTML do
|
||||
@moduledoc """
|
||||
This module is invoked by your endpoint in case of errors on HTML requests.
|
||||
|
||||
See config/config.exs.
|
||||
"""
|
||||
use SecDashboardWeb, :html
|
||||
use BulwarkWeb, :html
|
||||
|
||||
# If you want to customize your error pages,
|
||||
# uncomment the embed_templates/1 call below
|
||||
# and add pages to the error directory:
|
||||
#
|
||||
# * lib/sec_dashboard_web/controllers/error_html/404.html.heex
|
||||
# * lib/sec_dashboard_web/controllers/error_html/500.html.heex
|
||||
# * lib/bulwark_web/controllers/error_html/404.html.heex
|
||||
# * lib/bulwark_web/controllers/error_html/500.html.heex
|
||||
#
|
||||
# embed_templates "error_html/*"
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
defmodule SecDashboardWeb.ErrorJSON do
|
||||
defmodule BulwarkWeb.ErrorJSON do
|
||||
@moduledoc """
|
||||
This module is invoked by your endpoint in case of errors on JSON requests.
|
||||
|
||||
@@ -1,12 +1,12 @@
|
||||
defmodule SecDashboardWeb.Endpoint do
|
||||
use Phoenix.Endpoint, otp_app: :sec_dashboard
|
||||
defmodule BulwarkWeb.Endpoint do
|
||||
use Phoenix.Endpoint, otp_app: :bulwark
|
||||
|
||||
# The session will be stored in the cookie and signed,
|
||||
# this means its contents can be read but not tampered with.
|
||||
# Set :encryption_salt if you would also like to encrypt it.
|
||||
@session_options [
|
||||
store: :cookie,
|
||||
key: "_sec_dashboard_key",
|
||||
key: "_bulwark_key",
|
||||
signing_salt: "5HkUj33c",
|
||||
same_site: "Lax"
|
||||
]
|
||||
@@ -22,9 +22,9 @@ defmodule SecDashboardWeb.Endpoint do
|
||||
# static files generated by running `phx.digest`.
|
||||
plug Plug.Static,
|
||||
at: "/",
|
||||
from: :sec_dashboard,
|
||||
from: :bulwark,
|
||||
gzip: not code_reloading?,
|
||||
only: SecDashboardWeb.static_paths()
|
||||
only: BulwarkWeb.static_paths()
|
||||
|
||||
# Code reloading can be explicitly enabled under the
|
||||
# :code_reloader configuration of your endpoint.
|
||||
@@ -32,7 +32,7 @@ defmodule SecDashboardWeb.Endpoint do
|
||||
socket "/phoenix/live_reload/socket", Phoenix.LiveReloader.Socket
|
||||
plug Phoenix.LiveReloader
|
||||
plug Phoenix.CodeReloader
|
||||
plug Phoenix.Ecto.CheckRepoStatus, otp_app: :sec_dashboard
|
||||
plug Phoenix.Ecto.CheckRepoStatus, otp_app: :bulwark
|
||||
end
|
||||
|
||||
plug Phoenix.LiveDashboard.RequestLogger,
|
||||
@@ -50,5 +50,5 @@ defmodule SecDashboardWeb.Endpoint do
|
||||
plug Plug.MethodOverride
|
||||
plug Plug.Head
|
||||
plug Plug.Session, @session_options
|
||||
plug SecDashboardWeb.Router
|
||||
plug BulwarkWeb.Router
|
||||
end
|
||||
@@ -1,4 +1,4 @@
|
||||
defmodule SecDashboardWeb.Gettext do
|
||||
defmodule BulwarkWeb.Gettext do
|
||||
@moduledoc """
|
||||
A module providing Internationalization with a gettext-based API.
|
||||
|
||||
@@ -6,7 +6,7 @@ defmodule SecDashboardWeb.Gettext do
|
||||
that you can use in your application. To use this Gettext backend module,
|
||||
call `use Gettext` and pass it as an option:
|
||||
|
||||
use Gettext, backend: SecDashboardWeb.Gettext
|
||||
use Gettext, backend: BulwarkWeb.Gettext
|
||||
|
||||
# Simple translation
|
||||
gettext("Here is the string to translate")
|
||||
@@ -21,5 +21,5 @@ defmodule SecDashboardWeb.Gettext do
|
||||
|
||||
See the [Gettext Docs](https://hexdocs.pm/gettext) for detailed usage.
|
||||
"""
|
||||
use Gettext.Backend, otp_app: :sec_dashboard
|
||||
use Gettext.Backend, otp_app: :bulwark
|
||||
end
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
defmodule SecDashboardWeb.AssetLive.Index do
|
||||
defmodule BulwarkWeb.AssetLive.Index do
|
||||
@moduledoc """
|
||||
LiveView for listing assets at `/assets`.
|
||||
|
||||
@@ -6,9 +6,9 @@ defmodule SecDashboardWeb.AssetLive.Index do
|
||||
packages, repositories, filesystems) with text search on identifier and
|
||||
type quick-filter pills.
|
||||
"""
|
||||
use SecDashboardWeb, :live_view
|
||||
use BulwarkWeb, :live_view
|
||||
|
||||
alias SecDashboard.Security
|
||||
alias Bulwark.Security
|
||||
|
||||
@impl true
|
||||
def mount(_params, _session, socket) do
|
||||
+3
-3
@@ -1,13 +1,13 @@
|
||||
defmodule SecDashboardWeb.AssetLive.Show do
|
||||
defmodule BulwarkWeb.AssetLive.Show do
|
||||
@moduledoc """
|
||||
LiveView for displaying a single asset's details at `/assets/:id`.
|
||||
|
||||
Shows asset metadata (type, identifier, key-value metadata) and a
|
||||
Flop-paginated table of all findings associated with this asset.
|
||||
"""
|
||||
use SecDashboardWeb, :live_view
|
||||
use BulwarkWeb, :live_view
|
||||
|
||||
alias SecDashboard.Security
|
||||
alias Bulwark.Security
|
||||
|
||||
@impl true
|
||||
def mount(_params, _session, socket) do
|
||||
+5
-5
@@ -1,4 +1,4 @@
|
||||
defmodule SecDashboardWeb.DashboardLive do
|
||||
defmodule BulwarkWeb.DashboardLive do
|
||||
@moduledoc """
|
||||
LiveView for the security dashboard overview at `/`.
|
||||
|
||||
@@ -6,15 +6,15 @@ defmodule SecDashboardWeb.DashboardLive do
|
||||
recent scans, and recently discovered vulnerabilities. Updates in real-time
|
||||
via PubSub when scans complete or findings are triaged.
|
||||
"""
|
||||
use SecDashboardWeb, :live_view
|
||||
use BulwarkWeb, :live_view
|
||||
|
||||
alias SecDashboard.Security
|
||||
alias Bulwark.Security
|
||||
|
||||
@impl true
|
||||
def mount(_params, _session, socket) do
|
||||
if connected?(socket) do
|
||||
Phoenix.PubSub.subscribe(SecDashboard.PubSub, "scans")
|
||||
Phoenix.PubSub.subscribe(SecDashboard.PubSub, "findings")
|
||||
Phoenix.PubSub.subscribe(Bulwark.PubSub, "scans")
|
||||
Phoenix.PubSub.subscribe(Bulwark.PubSub, "findings")
|
||||
end
|
||||
|
||||
socket =
|
||||
+4
-4
@@ -1,4 +1,4 @@
|
||||
defmodule SecDashboardWeb.FindingLive.Index do
|
||||
defmodule BulwarkWeb.FindingLive.Index do
|
||||
@moduledoc """
|
||||
LiveView for listing and triaging findings at `/findings`.
|
||||
|
||||
@@ -6,14 +6,14 @@ defmodule SecDashboardWeb.FindingLive.Index do
|
||||
(acknowledge, resolve, mark as false positive, reopen) and status quick-filter
|
||||
pills. Subscribes to the `"findings"` PubSub topic for real-time status updates.
|
||||
"""
|
||||
use SecDashboardWeb, :live_view
|
||||
use BulwarkWeb, :live_view
|
||||
|
||||
alias SecDashboard.Security
|
||||
alias Bulwark.Security
|
||||
|
||||
@impl true
|
||||
def mount(_params, _session, socket) do
|
||||
if connected?(socket) do
|
||||
Phoenix.PubSub.subscribe(SecDashboard.PubSub, "findings")
|
||||
Phoenix.PubSub.subscribe(Bulwark.PubSub, "findings")
|
||||
end
|
||||
|
||||
socket =
|
||||
+6
-6
@@ -1,4 +1,4 @@
|
||||
defmodule SecDashboardWeb.ScanLive.Index do
|
||||
defmodule BulwarkWeb.ScanLive.Index do
|
||||
@moduledoc """
|
||||
LiveView for listing and uploading scans at `/scans`.
|
||||
|
||||
@@ -6,17 +6,17 @@ defmodule SecDashboardWeb.ScanLive.Index do
|
||||
updates via PubSub. Includes the file upload form for ingesting new
|
||||
security artifacts.
|
||||
"""
|
||||
use SecDashboardWeb, :live_view
|
||||
use BulwarkWeb, :live_view
|
||||
|
||||
alias SecDashboard.Security
|
||||
alias SecDashboard.Ingestion.{Detector, ParseJob}
|
||||
alias Bulwark.Security
|
||||
alias Bulwark.Ingestion.{Detector, ParseJob}
|
||||
|
||||
@upload_dir Application.compile_env(:sec_dashboard, :upload_dir, "priv/uploads")
|
||||
@upload_dir Application.compile_env(:bulwark, :upload_dir, "priv/uploads")
|
||||
|
||||
@impl true
|
||||
def mount(_params, _session, socket) do
|
||||
if connected?(socket) do
|
||||
Phoenix.PubSub.subscribe(SecDashboard.PubSub, "scans")
|
||||
Phoenix.PubSub.subscribe(Bulwark.PubSub, "scans")
|
||||
end
|
||||
|
||||
socket =
|
||||
+4
-4
@@ -1,4 +1,4 @@
|
||||
defmodule SecDashboardWeb.ScanLive.Show do
|
||||
defmodule BulwarkWeb.ScanLive.Show do
|
||||
@moduledoc """
|
||||
LiveView for displaying a single scan's details at `/scans/:id`.
|
||||
|
||||
@@ -6,9 +6,9 @@ defmodule SecDashboardWeb.ScanLive.Show do
|
||||
table of findings from that scan. Subscribes to per-scan PubSub updates
|
||||
for real-time status changes.
|
||||
"""
|
||||
use SecDashboardWeb, :live_view
|
||||
use BulwarkWeb, :live_view
|
||||
|
||||
alias SecDashboard.Security
|
||||
alias Bulwark.Security
|
||||
|
||||
@impl true
|
||||
def mount(_params, _session, socket) do
|
||||
@@ -20,7 +20,7 @@ defmodule SecDashboardWeb.ScanLive.Show do
|
||||
scan = Security.get_scan!(id)
|
||||
|
||||
if connected?(socket) do
|
||||
Phoenix.PubSub.subscribe(SecDashboard.PubSub, "scan:#{id}")
|
||||
Phoenix.PubSub.subscribe(Bulwark.PubSub, "scan:#{id}")
|
||||
end
|
||||
|
||||
case Security.list_findings_for_scan(scan.id, params) do
|
||||
@@ -1,4 +1,4 @@
|
||||
defmodule SecDashboardWeb.SettingsLive do
|
||||
defmodule BulwarkWeb.SettingsLive do
|
||||
@moduledoc """
|
||||
LiveView for application display settings at `/settings`.
|
||||
|
||||
@@ -6,7 +6,7 @@ defmodule SecDashboardWeb.SettingsLive do
|
||||
The hook pushes current values to the server on mount so toggles render
|
||||
correctly, and handles persistence when the user changes a setting.
|
||||
"""
|
||||
use SecDashboardWeb, :live_view
|
||||
use BulwarkWeb, :live_view
|
||||
|
||||
@impl true
|
||||
def mount(_params, _session, socket) do
|
||||
+3
-3
@@ -1,4 +1,4 @@
|
||||
defmodule SecDashboardWeb.VulnerabilityLive.Index do
|
||||
defmodule BulwarkWeb.VulnerabilityLive.Index do
|
||||
@moduledoc """
|
||||
LiveView for listing vulnerabilities at `/vulnerabilities`.
|
||||
|
||||
@@ -6,9 +6,9 @@ defmodule SecDashboardWeb.VulnerabilityLive.Index do
|
||||
with severity badges, text search across CVE IDs and titles, and severity
|
||||
quick-filter pills.
|
||||
"""
|
||||
use SecDashboardWeb, :live_view
|
||||
use BulwarkWeb, :live_view
|
||||
|
||||
alias SecDashboard.Security
|
||||
alias Bulwark.Security
|
||||
|
||||
@impl true
|
||||
def mount(_params, _session, socket) do
|
||||
+3
-3
@@ -1,13 +1,13 @@
|
||||
defmodule SecDashboardWeb.VulnerabilityLive.Show do
|
||||
defmodule BulwarkWeb.VulnerabilityLive.Show do
|
||||
@moduledoc """
|
||||
LiveView for displaying a single vulnerability's details at `/vulnerabilities/:id`.
|
||||
|
||||
Shows vulnerability metadata (severity, description, references) and a
|
||||
Flop-paginated table of all findings associated with this vulnerability.
|
||||
"""
|
||||
use SecDashboardWeb, :live_view
|
||||
use BulwarkWeb, :live_view
|
||||
|
||||
alias SecDashboard.Security
|
||||
alias Bulwark.Security
|
||||
|
||||
@impl true
|
||||
def mount(_params, _session, socket) do
|
||||
@@ -1,11 +1,11 @@
|
||||
defmodule SecDashboardWeb.Router do
|
||||
use SecDashboardWeb, :router
|
||||
defmodule BulwarkWeb.Router do
|
||||
use BulwarkWeb, :router
|
||||
|
||||
pipeline :browser do
|
||||
plug :accepts, ["html"]
|
||||
plug :fetch_session
|
||||
plug :fetch_live_flash
|
||||
plug :put_root_layout, html: {SecDashboardWeb.Layouts, :root}
|
||||
plug :put_root_layout, html: {BulwarkWeb.Layouts, :root}
|
||||
plug :protect_from_forgery
|
||||
plug :put_secure_browser_headers
|
||||
end
|
||||
@@ -14,7 +14,7 @@ defmodule SecDashboardWeb.Router do
|
||||
plug :accepts, ["json"]
|
||||
end
|
||||
|
||||
scope "/", SecDashboardWeb do
|
||||
scope "/", BulwarkWeb do
|
||||
pipe_through :browser
|
||||
|
||||
live "/", DashboardLive
|
||||
@@ -29,12 +29,12 @@ defmodule SecDashboardWeb.Router do
|
||||
end
|
||||
|
||||
# Other scopes may use custom stacks.
|
||||
# scope "/api", SecDashboardWeb do
|
||||
# scope "/api", BulwarkWeb do
|
||||
# pipe_through :api
|
||||
# end
|
||||
|
||||
# Enable LiveDashboard and Swoosh mailbox preview in development
|
||||
if Application.compile_env(:sec_dashboard, :dev_routes) do
|
||||
if Application.compile_env(:bulwark, :dev_routes) do
|
||||
# If you want to use the LiveDashboard in production, you should put
|
||||
# it behind authentication and allow only admins to access it.
|
||||
# If your application does not have an admins-only section yet,
|
||||
@@ -45,7 +45,7 @@ defmodule SecDashboardWeb.Router do
|
||||
scope "/dev" do
|
||||
pipe_through :browser
|
||||
|
||||
live_dashboard "/dashboard", metrics: SecDashboardWeb.Telemetry
|
||||
live_dashboard "/dashboard", metrics: BulwarkWeb.Telemetry
|
||||
forward "/mailbox", Plug.Swoosh.MailboxPreview
|
||||
end
|
||||
end
|
||||
@@ -1,4 +1,4 @@
|
||||
defmodule SecDashboardWeb.Telemetry do
|
||||
defmodule BulwarkWeb.Telemetry do
|
||||
use Supervisor
|
||||
import Telemetry.Metrics
|
||||
|
||||
@@ -53,23 +53,23 @@ defmodule SecDashboardWeb.Telemetry do
|
||||
),
|
||||
|
||||
# Database Metrics
|
||||
summary("sec_dashboard.repo.query.total_time",
|
||||
summary("bulwark.repo.query.total_time",
|
||||
unit: {:native, :millisecond},
|
||||
description: "The sum of the other measurements"
|
||||
),
|
||||
summary("sec_dashboard.repo.query.decode_time",
|
||||
summary("bulwark.repo.query.decode_time",
|
||||
unit: {:native, :millisecond},
|
||||
description: "The time spent decoding the data received from the database"
|
||||
),
|
||||
summary("sec_dashboard.repo.query.query_time",
|
||||
summary("bulwark.repo.query.query_time",
|
||||
unit: {:native, :millisecond},
|
||||
description: "The time spent executing the query"
|
||||
),
|
||||
summary("sec_dashboard.repo.query.queue_time",
|
||||
summary("bulwark.repo.query.queue_time",
|
||||
unit: {:native, :millisecond},
|
||||
description: "The time spent waiting for a database connection"
|
||||
),
|
||||
summary("sec_dashboard.repo.query.idle_time",
|
||||
summary("bulwark.repo.query.idle_time",
|
||||
unit: {:native, :millisecond},
|
||||
description:
|
||||
"The time the connection spent waiting before being checked out for the query"
|
||||
@@ -87,7 +87,7 @@ defmodule SecDashboardWeb.Telemetry do
|
||||
[
|
||||
# A module, function and arguments to be invoked periodically.
|
||||
# This function must call :telemetry.execute/3 and a metric must be added above.
|
||||
# {SecDashboardWeb, :count_users, []}
|
||||
# {BulwarkWeb, :count_users, []}
|
||||
]
|
||||
end
|
||||
end
|
||||
@@ -1,3 +0,0 @@
|
||||
defmodule SecDashboard.Mailer do
|
||||
use Swoosh.Mailer, otp_app: :sec_dashboard
|
||||
end
|
||||
@@ -1,5 +0,0 @@
|
||||
defmodule SecDashboard.Repo do
|
||||
use Ecto.Repo,
|
||||
otp_app: :sec_dashboard,
|
||||
adapter: Ecto.Adapters.Postgres
|
||||
end
|
||||
@@ -1,9 +1,9 @@
|
||||
defmodule SecDashboard.MixProject do
|
||||
defmodule Bulwark.MixProject do
|
||||
use Mix.Project
|
||||
|
||||
def project do
|
||||
[
|
||||
app: :sec_dashboard,
|
||||
app: :bulwark,
|
||||
version: "0.1.0",
|
||||
elixir: "~> 1.15",
|
||||
elixirc_paths: elixirc_paths(Mix.env()),
|
||||
@@ -20,7 +20,7 @@ defmodule SecDashboard.MixProject do
|
||||
# Type `mix help compile.app` for more information.
|
||||
def application do
|
||||
[
|
||||
mod: {SecDashboard.Application, []},
|
||||
mod: {Bulwark.Application, []},
|
||||
extra_applications: [:logger, :runtime_tools]
|
||||
]
|
||||
end
|
||||
@@ -85,10 +85,10 @@ defmodule SecDashboard.MixProject do
|
||||
"ecto.reset": ["ecto.drop", "ecto.setup"],
|
||||
test: ["ecto.create --quiet", "ecto.migrate --quiet", "test"],
|
||||
"assets.setup": ["tailwind.install --if-missing", "esbuild.install --if-missing"],
|
||||
"assets.build": ["compile", "tailwind sec_dashboard", "esbuild sec_dashboard"],
|
||||
"assets.build": ["compile", "tailwind bulwark", "esbuild bulwark"],
|
||||
"assets.deploy": [
|
||||
"tailwind sec_dashboard --minify",
|
||||
"esbuild sec_dashboard --minify",
|
||||
"tailwind bulwark --minify",
|
||||
"esbuild bulwark --minify",
|
||||
"phx.digest"
|
||||
],
|
||||
precommit: ["compile --warning-as-errors", "deps.unlock --unused", "format", "test"]
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
defmodule SecDashboard.Repo.Migrations.AddOban do
|
||||
defmodule Bulwark.Repo.Migrations.AddOban do
|
||||
use Ecto.Migration
|
||||
|
||||
def up, do: Oban.Migrations.up()
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
defmodule SecDashboard.Repo.Migrations.CreateSecurityTables do
|
||||
defmodule Bulwark.Repo.Migrations.CreateSecurityTables do
|
||||
use Ecto.Migration
|
||||
|
||||
def change do
|
||||
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
# Inside the script, you can read and write to any of your
|
||||
# repositories directly:
|
||||
#
|
||||
# SecDashboard.Repo.insert!(%SecDashboard.SomeSchema{})
|
||||
# Bulwark.Repo.insert!(%Bulwark.SomeSchema{})
|
||||
#
|
||||
# We recommend using the bang functions (`insert!`, `update!`
|
||||
# and so on) as they will fail if something goes wrong.
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
defmodule BulwarkWeb.ErrorHTMLTest do
|
||||
use BulwarkWeb.ConnCase, async: true
|
||||
|
||||
# Bring render_to_string/4 for testing custom views
|
||||
import Phoenix.Template, only: [render_to_string: 4]
|
||||
|
||||
test "renders 404.html" do
|
||||
assert render_to_string(BulwarkWeb.ErrorHTML, "404", "html", []) == "Not Found"
|
||||
end
|
||||
|
||||
test "renders 500.html" do
|
||||
assert render_to_string(BulwarkWeb.ErrorHTML, "500", "html", []) ==
|
||||
"Internal Server Error"
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,12 @@
|
||||
defmodule BulwarkWeb.ErrorJSONTest do
|
||||
use BulwarkWeb.ConnCase, async: true
|
||||
|
||||
test "renders 404" do
|
||||
assert BulwarkWeb.ErrorJSON.render("404.json", %{}) == %{errors: %{detail: "Not Found"}}
|
||||
end
|
||||
|
||||
test "renders 500" do
|
||||
assert BulwarkWeb.ErrorJSON.render("500.json", %{}) ==
|
||||
%{errors: %{detail: "Internal Server Error"}}
|
||||
end
|
||||
end
|
||||
@@ -1,15 +0,0 @@
|
||||
defmodule SecDashboardWeb.ErrorHTMLTest do
|
||||
use SecDashboardWeb.ConnCase, async: true
|
||||
|
||||
# Bring render_to_string/4 for testing custom views
|
||||
import Phoenix.Template, only: [render_to_string: 4]
|
||||
|
||||
test "renders 404.html" do
|
||||
assert render_to_string(SecDashboardWeb.ErrorHTML, "404", "html", []) == "Not Found"
|
||||
end
|
||||
|
||||
test "renders 500.html" do
|
||||
assert render_to_string(SecDashboardWeb.ErrorHTML, "500", "html", []) ==
|
||||
"Internal Server Error"
|
||||
end
|
||||
end
|
||||
@@ -1,12 +0,0 @@
|
||||
defmodule SecDashboardWeb.ErrorJSONTest do
|
||||
use SecDashboardWeb.ConnCase, async: true
|
||||
|
||||
test "renders 404" do
|
||||
assert SecDashboardWeb.ErrorJSON.render("404.json", %{}) == %{errors: %{detail: "Not Found"}}
|
||||
end
|
||||
|
||||
test "renders 500" do
|
||||
assert SecDashboardWeb.ErrorJSON.render("500.json", %{}) ==
|
||||
%{errors: %{detail: "Internal Server Error"}}
|
||||
end
|
||||
end
|
||||
@@ -1,4 +1,4 @@
|
||||
defmodule SecDashboardWeb.ConnCase do
|
||||
defmodule BulwarkWeb.ConnCase do
|
||||
@moduledoc """
|
||||
This module defines the test case to be used by
|
||||
tests that require setting up a connection.
|
||||
@@ -11,7 +11,7 @@ defmodule SecDashboardWeb.ConnCase do
|
||||
we enable the SQL sandbox, so changes done to the database
|
||||
are reverted at the end of every test. If you are using
|
||||
PostgreSQL, you can even run database tests asynchronously
|
||||
by setting `use SecDashboardWeb.ConnCase, async: true`, although
|
||||
by setting `use BulwarkWeb.ConnCase, async: true`, although
|
||||
this option is not recommended for other databases.
|
||||
"""
|
||||
|
||||
@@ -20,19 +20,19 @@ defmodule SecDashboardWeb.ConnCase do
|
||||
using do
|
||||
quote do
|
||||
# The default endpoint for testing
|
||||
@endpoint SecDashboardWeb.Endpoint
|
||||
@endpoint BulwarkWeb.Endpoint
|
||||
|
||||
use SecDashboardWeb, :verified_routes
|
||||
use BulwarkWeb, :verified_routes
|
||||
|
||||
# Import conveniences for testing with connections
|
||||
import Plug.Conn
|
||||
import Phoenix.ConnTest
|
||||
import SecDashboardWeb.ConnCase
|
||||
import BulwarkWeb.ConnCase
|
||||
end
|
||||
end
|
||||
|
||||
setup tags do
|
||||
SecDashboard.DataCase.setup_sandbox(tags)
|
||||
Bulwark.DataCase.setup_sandbox(tags)
|
||||
{:ok, conn: Phoenix.ConnTest.build_conn()}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
defmodule SecDashboard.DataCase do
|
||||
defmodule Bulwark.DataCase do
|
||||
@moduledoc """
|
||||
This module defines the setup for tests requiring
|
||||
access to the application's data layer.
|
||||
@@ -10,7 +10,7 @@ defmodule SecDashboard.DataCase do
|
||||
we enable the SQL sandbox, so changes done to the database
|
||||
are reverted at the end of every test. If you are using
|
||||
PostgreSQL, you can even run database tests asynchronously
|
||||
by setting `use SecDashboard.DataCase, async: true`, although
|
||||
by setting `use Bulwark.DataCase, async: true`, although
|
||||
this option is not recommended for other databases.
|
||||
"""
|
||||
|
||||
@@ -18,17 +18,17 @@ defmodule SecDashboard.DataCase do
|
||||
|
||||
using do
|
||||
quote do
|
||||
alias SecDashboard.Repo
|
||||
alias Bulwark.Repo
|
||||
|
||||
import Ecto
|
||||
import Ecto.Changeset
|
||||
import Ecto.Query
|
||||
import SecDashboard.DataCase
|
||||
import Bulwark.DataCase
|
||||
end
|
||||
end
|
||||
|
||||
setup tags do
|
||||
SecDashboard.DataCase.setup_sandbox(tags)
|
||||
Bulwark.DataCase.setup_sandbox(tags)
|
||||
:ok
|
||||
end
|
||||
|
||||
@@ -36,7 +36,7 @@ defmodule SecDashboard.DataCase do
|
||||
Sets up the sandbox based on the test tags.
|
||||
"""
|
||||
def setup_sandbox(tags) do
|
||||
pid = Ecto.Adapters.SQL.Sandbox.start_owner!(SecDashboard.Repo, shared: not tags[:async])
|
||||
pid = Ecto.Adapters.SQL.Sandbox.start_owner!(Bulwark.Repo, shared: not tags[:async])
|
||||
on_exit(fn -> Ecto.Adapters.SQL.Sandbox.stop_owner(pid) end)
|
||||
end
|
||||
|
||||
|
||||
@@ -1,2 +1,2 @@
|
||||
ExUnit.start()
|
||||
Ecto.Adapters.SQL.Sandbox.mode(SecDashboard.Repo, :manual)
|
||||
Ecto.Adapters.SQL.Sandbox.mode(Bulwark.Repo, :manual)
|
||||
|
||||
Reference in New Issue
Block a user