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:
Christopher Fahlin
2026-05-13 21:15:40 -07:00
parent 89ce5a29d5
commit 303e2c9c60
58 changed files with 228 additions and 229 deletions
+5 -5
View File
@@ -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
+5 -5
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
View File
@@ -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
+2 -2
View File
@@ -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 """
@@ -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
@@ -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
@@ -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
@@ -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
+3
View File
@@ -0,0 +1,3 @@
defmodule Bulwark.Mailer do
use Swoosh.Mailer, otp_app: :bulwark
end
+5
View File
@@ -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
+10 -10
View File
@@ -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
@@ -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/*"
@@ -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,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
@@ -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
@@ -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
@@ -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 =
@@ -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 =
@@ -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 =
@@ -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
@@ -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
@@ -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
-3
View File
@@ -1,3 +0,0 @@
defmodule SecDashboard.Mailer do
use Swoosh.Mailer, otp_app: :sec_dashboard
end
-5
View File
@@ -1,5 +0,0 @@
defmodule SecDashboard.Repo do
use Ecto.Repo,
otp_app: :sec_dashboard,
adapter: Ecto.Adapters.Postgres
end
+6 -6
View File
@@ -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
View File
@@ -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
+6 -6
View File
@@ -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
+6 -6
View File
@@ -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 -1
View File
@@ -1,2 +1,2 @@
ExUnit.start()
Ecto.Adapters.SQL.Sandbox.mode(SecDashboard.Repo, :manual)
Ecto.Adapters.SQL.Sandbox.mode(Bulwark.Repo, :manual)